{"record":{"id":"75f99fc2175160e6","repo":"dotnet/aspnetcore","slug":"the-parameter-parametername-accepts-a-complex","errorCode":null,"errorMessage":"The parameter '${parameterName}' accepts a complex-typed object so it cannot be set using an attribute. Try setting it as a element property instead.","messagePattern":"The parameter '(.+?)' accepts a complex-typed object so it cannot be set using an attribute\\. Try setting it as a element property instead\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/Components/CustomElements/src/js/BlazorCustomElements.ts","lineNumber":134,"sourceCode":"          case 'false':\n          case 'False':\n            return false;\n          default:\n            throw new Error(`Invalid boolean value '${attributeValue}' for parameter '${parameterName}'`);\n        }\n      case 'number':\n        const number = Number(attributeValue);\n        if (Number.isNaN(number)) {\n          throw new Error(`Invalid number value '${attributeValue}' for parameter '${parameterName}'`);\n        } else {\n          return number;\n        }\n      case 'boolean?':\n        return attributeValue ? BlazorCustomElement.parseAttributeValue(attributeValue, 'boolean', parameterName) : null;\n      case 'number?':\n        return attributeValue ? BlazorCustomElement.parseAttributeValue(attributeValue, 'number', parameterName) : null;\n      case 'object':\n        throw new Error(`The parameter '${parameterName}' accepts a complex-typed object so it cannot be set using an attribute. Try setting it as a element property instead.`);\n      default:\n        throw new Error(`Unknown type '${type}' for parameter '${parameterName}'`);\n    }\n  }\n}\n\nfunction dasherize(value: string): string {\n  return camelCase(value).replace(/([A-Z])/g, \"-$1\").toLowerCase();\n}\n\nfunction camelCase(value: string): string {\n  return value[0].toLowerCase() + value.substring(1);\n}\n\ninterface JSComponentParameter {\n  name: string;\n  type: JSComponentParameterType;\n}","sourceCodeStart":116,"sourceCodeEnd":152,"githubUrl":"https://github.com/dotnet/aspnetcore/blob/294cab2f9b2e03af6b953820c7ab497c3c8b7ad9/src/Components/CustomElements/src/js/BlazorCustomElements.ts#L116-L152","documentation":"Thrown unconditionally by parseAttributeValue in the 'object' case. Complex-typed (object) parameters cannot be expressed as a string attribute, so the framework refuses to parse them; the only way to supply such a parameter is via the element's JS property, which is defined in the constructor for each mapped parameter.","triggerScenarios":"Declaring a [Parameter] of a complex type (class, array, nested object) on a Razor component exposed as a custom element, and then trying to set it via an HTML attribute: <my-component data=\"{a:1}\"/>. The framework detects type 'object' and throws.","commonSituations":"Components that take POCOs, lists, dictionaries, or component references as parameters and are registered via RegisterAsCustomElement. Authors naturally try attribute binding first and hit this.","solutions":["Set the value as a JS property: const el = document.querySelector('my-component'); el.data = { a: 1 }; — the constructor wires up a property setter per parameter (BlazorCustomElements.ts:50-65).","Redesign the parameter as a primitive (string JSON) and parse it inside the component, if you must use an attribute.","Split the complex parameter into multiple primitive [Parameter] properties that can each be set as attributes."],"exampleFix":"// before (throws)\n<my-chart options=\"{\\\"legend\\\":true}\"></my-chart>\n\n// after\nconst chart = document.querySelector('my-chart');\nchart.options = { legend: true };","handlingStrategy":"type-guard","validationCode":"function isComplexParamType(type: string): boolean {\n  return type === 'object';\n}\n\n// for each descriptor, decide attribute vs property\nfor (const p of parameterDescriptors) {\n  if (isComplexParamType(p.type)) {\n    el[p.name] = complexValue; // property, not attribute\n  } else {\n    el.setAttribute(dasherize(p.name), String(value));\n  }\n}","typeGuard":"type ComplexType = 'object';\nfunction isObjectParam(p: { type: string }): p is { type: ComplexType } {\n  return p.type === 'object';\n}","tryCatchPattern":"try {\n  el.setAttribute('options', JSON.stringify(value));\n} catch (e) {\n  if (/cannot be set using an attribute/.test((e as Error).message)) {\n    el.options = value; // fall back to property\n  } else throw e;\n}","preventionTips":["Never bind complex parameters via attributes; use the camelCase JS property.","Document for each custom element which parameters are 'object' so authors know to use properties.","Redesign complex parameters as multiple primitive parameters if attribute-binding is required.","In your binding layer, branch on the descriptor type before choosing attribute vs property."],"tags":["blazor-custom-elements","type-coercion","attributes","complex-types"],"analyzedSha":"294cab2f9b2e03af6b953820c7ab497c3c8b7ad9","analyzedAt":"2026-08-06T20:08:02.189Z","schemaVersion":2},"datasetVersion":"2026-08-06T23:17:07.152Z"}