preact-custom-element icon indicating copy to clipboard operation
preact-custom-element copied to clipboard

Hyphenated attributes and camelCased properties

Open raihle opened this issue 4 years ago • 0 comments

When a component is connected, preact-custom-element will loop through all attributes and set them as props on the component - both with the original casing and with a camelCased name. Automatic camelCasing is also done for observed attributes.

On the other hand, when determining which attributes to observe, the wrapper does not perform any corresponding transformation - it simply uses the given propNames directly (passed in explicitly, or extracted from the component definition). This is a problem because component props are usually in camelCase, while HTML attributes must be in lowercase (usually hyphenated).

If propNames are extracted from the component's propTypes, there is virtually no chance that they will be hyphenated, and the wrapper will only listen for (and try to reflect) changes to a camelCased attribute, not a hyphenated one. However, the spec requires attributes to be in lowercase, and attempting to set a camelCase attribute in a framework like Vue, manually through browser dev tools, or in the HTML source, will lead to a lowercase attribute being set instead. This effectively means that any prop name with a capital letter cannot be observed (as an attribute) by preact-custom-element. Initial values will still be set, since preact-custom-element loops through all attributes and converts them to camelCase props, but that only happens once. The DOM property will also work, but supporting the attribute - for simple data - would be nice.

propNames could be hyphenated if they are explicitly passed, or defined as observedAttributes on the component. But in this case the wrapper will set up a hyphenated DOM property instead of a camelCased one.


Should preact-custom-element camelCase all propNames before defining properties, and hyphenate them before setting observedAttributes?

  • This is the option I would prefer as a consumer, but I would like some feedback on the idea before putting together a PR

Should consumers pass in camelCased names for complex types (which will use properties) and hyphenated names for simple types (which will use attributes)? Maybe both forms for simple types?

  • This would avoid registering complex types as observedAttributes, which won't work anyways
  • This could probably be extracted automatically from propTypes, but would require some additional logic compared to just getting the names.

Should properties and attributes be separated in the preact-custom-element API?

  • Removes unnecessary observedAttributes (for properties) or defineProperty calls (for attributes)
  • Attributes and properties have some important differences. Maybe trying to abstract them into one thing isn't a good idea anyways?
  • Would probably be a breaking change, although perhaps compatibility could be maintained by using propNames in both places if the consumer does not specify

raihle avatar Oct 09 '20 15:10 raihle