core
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)
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:
- apply them as element attributes (
el.settAttribute('value', 'Test')) - 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
camelCaseprop 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
camelCaseattributes. That should be handled properly by the implementation, though - I think it's covered. tabindexattribute vstabIndexDOMProp. 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-haspopupvs.ariaHasPopup: Chrome has the latter as a DOMProp (FF doesn't). That domProp's name is not the camelCase Version of thearia-haspopupattribute. Kinda like the tabindex situation.