core icon indicating copy to clipboard operation
core copied to clipboard

fix(runtime-dom): ensure element attributes are always properly applied regardless of being passed in kebap-case or camelCase. (fix #5477)

Open LinusBorg opened this issue 2 years ago • 3 comments
trafficstars

This is a second attempt to solve #5477

I created this as a draft for now since I'm not sure this is the best approach / covers all bases

close: #5477

Situation

Vue has two different ways of applying the vnode's props to an element:

  1. apply them as element attributes (el.settAttribute('value', 'Test'))
  2. apply them as element properties (el.value = 'Test')

Vue prefers the second way if it can detect that property on the element (simplified: if (value in el), plus some exceptions/special cases.)

As no* regular HTML attribute contains a hyphen, kebab-case vs. camelCase is usually not an issue, but there are two important exceptions:

  • all aria- attributes.
  • any custom Attributes can contain hyphens (or be camelCased element properties). These are usually used on custom elements ("web components")

The problem

When a hyphenated or camelCased vnode prop is processed in patchProp, we can experience a few related but distinct undesirable bugs.

prop Has DOMprop? handled correctly? result
id applied as DOMprop id
aria-label ❌ (expected) applied as attribute aria-label
ariaControls ❌ (expected) 🚸 applied as attribute ariacontrols (1)
custom-attr customAttr (in web comp.) 🚸 applied as attribute custom-attr (2a), though
customAttr 🚸 applied as DOMprop customAttr (2b)

Problem (1):

a camelCase prop is applied as lowercase attribute (missing hyphen)

Problem (2):

  • kebap-caseprop applied as attribute even though matching camelCase DOM property exists.
  • while camelCase prop is applied to element via the matching DOM property.

This can lead to problems with custom elements. For example, if the custom element's prop blogPost expects a post object, that has to be passed as a DOMprop. Applying it as an attribute will result in blog-post="[Object object]".

Solution

  • When checking wether or not a raw prop should be applied as an attribute or a DOMprop: camelize first.
  • If a raw prop should be applied as an attribute: hyphenate it.
  • If a raw prop should be applied as a DOMprop: camelize it.

Things things to consider / Open questions.

  • Is this a perf hit in this hot path of patching elements?.
  • Is this a breaking change? I don't really think so, but there might be userland implementations right now that implicitly rely on the currently broken implementation.
  • SVGs can have camelCase attributes. That should be handled properly by the implementation, though - I think it's covered.
  • tabindex attribute vs tabIndex DOMProp. Don't think this is a problem either but it feels worth mentioning as it's the only instance I can think of where a regular HTML attribute has a camelCase counterpart.
  • aria-haspopup vs. ariaHasPopup: Chrome has the latter as a DOMProp (FF doesn't). That domProp's name is not the camelCase Version of the aria-haspopup attribute. Kinda like the tabindex situation.

LinusBorg avatar Dec 23 '22 20:12 LinusBorg