webcomponents / webcomponents/polyfills
[Custom Elements] Incorrect `observedAttributes` behavior when using mixed-case attributes
- Dominant language
- HTML
- Stars
- 1.2k
- Forks
- 168
- PR merge metrics
- No merged PRs in 30d
Description
### Description
Another issue that is somewhat related, and may be relevant to also see for context: https://github.com/webcomponents/polyfills/issues/111
With native Custom Elements, the attributes declared in the static `observedAttributes` getter _must_ be lower-case in order for the `attributeChangedCallback` to be triggered when they change. This is how the implementation in Chrome, Firefox, and Safari works.
In the following example, the `attributeChangedCallback` will never be called in browsers that natively support Custom Elements:
```js
class A extends HTMLElement {
static get observedAttributes () {
return ["fooBarBaz"];
}
attributeChangedCallback (name, oldValue, newValue) {
console.log("changed!:", {
name, oldValue, newValue
});
}
}
customElements.define("a-el", A);
const a = new A();
// Won't trigger attributeChangedCallback
console.log("setting attribute with name: 'foobarbaz'");
a.setAttribute("foobarbaz", "");
// Wait a bit since MutationObserver operates on the microtask queue
setTimeout(() => {
// *Will* trigger attributeChangedCallback but **only when using the Custom Elements polyfill**
console.log("setting attribute with name: 'fooBarBaz'");
a.setAttribute("fooBarBaz", "");
}, 1000);
```
However, using the Custom Elements polyfill, the `attributeChangedCallback` **will** be called when there is a direct case-sensitive match between the observed attribute name and the attribute named passed on to `setAttribute`. In the example above, the second call (`a.setAttribute("fooBarBaz", "")`) will trigger the `attributeChangedCallback`.
While - according to the HTML spec - attribute names can mix lower- with uppercase letters that are an ASCII case-insensitive match for the attribute's name, the actual behavior of `observedAttributes` does require, at least as evidenced by its implementation in Chromium/WebKit/Firefox, that these names are all lowercased when returned from that getter.
For lit-html/LitElement users and users of other tools and libraries that leverages Custom Elements, this can cause problems when binding to attributes or boolean attributes with mixed-case property names as is very common to do (camelCased property names that reflect to/from attributes) when leveraging the Custom Elements polyfill.
### Example
Here's a repro. Open the page, and check out the console. What is printed there depends on whether or not the polyfill is being used.
https://ce-bug-demo.surge.sh/
### Steps to reproduce
A repro example is provided in the code example above
#### Expected behavior
The behavior of `observedAttributes` aligns with native behavior.
#### Actual behavior
The behavior of `observedAttributes` does not align with native behavior.
### Version
@webcomponents/custom-elements@1.4.2
### Browsers affected
- [x] Chrome
- [x] Firefox
- [x] Edge
- [x] Safari
- [x] IE 11
Contributor guide
Assessment
This issue has not been assessed yet.