Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Custom Elements v1 (and v0) #516

merged 9 commits into from Jul 26, 2018

Custom Elements v1 (and v0) #516

merged 9 commits into from Jul 26, 2018


Copy link

@javan javan commented Jul 3, 2018

This pull requests adds support for Custom Elements v1, the official standardized spec recognized by all major platforms. v1 has already landed in Chrome, Safari, and Opera, and development is underway in Firefox and Microsoft Edge.

Custom Elements v1 and v0 are conceptually identical, although they don't share much in common API-wise. For better or worse, those API differences make v1 more difficult to adopt (unless you're only targeting modern browsers and delivering ES2015+ JavaScript code).

v1 gotchas…

Caveat: an unpolyfillable upgrade
There are things that current V1 makes impossible to reproduce via plain JS and the most obvious is the JS instance upgrade. In older engines, extending any DOM native class is not enough to have a proper DOM instance.

ES5 vs ES2015
The custom elements v1 spec is not compatible with ES5 style classes. This means ES2015 code compiled to ES5 will not work with a native implementation of Custom Elements.[0] While it's possible to force the custom elements polyfill to be used to workaround this issue (by setting (customElements.forcePolyfill = true; before loading the polyfill), you will not be using the UA's native implementation in that case.

Since this is not ideal, we've provided an alternative: native-shim.js. Loading this shim minimally augments the native implementation to be compatible with ES5 code. We are also working on some future refinements to this approach that will improve the implementation and automatically detect if it's needed.

[0] The spec requires that an element call the HTMLElement constructor. Typically an ES5 style class would do something like to emulate super(). However, HTMLElement must be called as a constructor and not as a plain function, i.e. with Reflect.construct(HTMLElement, [], MyCEConstructor), or it will throw.

In my testing, none of the v1 polyfills worked reliably in older versions of Safari or on older Android devices. They're also far more invasive, attempting to patch every possible means of content creation / insertion. Miss one (like Element#insertAdjacentHTML) and custom elements slip through without upgrading.

v0 on the other hand, even though it's only officially supported in Chrome, has far better support thanks to several battle hardened, MutationObserver-based polyfills. And so, this pull requests preserves support for v0 too.

To smooth over the v1/v0 API differences, this change introduces its own distinct naming convention for lifecycle callbacks: initialize(), connect(), disconnect() (thanks, Stimulus!), and automatically maps them to the supported custom element API.


initialize() → connectedCallback() (once)
connect()    → connectedCallback()
disconnect() → disconnectedCallback()

v0 (polyfilled if necessary):

initialize() → createdCallback() 
connect()    → attachedCallback()
disconnect() → detachedCallback()

Fixes #495

Copy link

Nice strategy!

Safari doesn't seem to like the nuclear option
@javan javan merged commit d72ab77 into master Jul 26, 2018
@javan javan deleted the custom-elements-v1-or-v0 branch July 26, 2018 15:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
None yet
None yet

Successfully merging this pull request may close these issues.

None yet

2 participants