Custom elements let authors create their own elements, with their own methods, behavior, and attribute handling. Custom elements shipped in M33. We colloquially refer to that version as “v0.”
Contact Dominic Cooney (dominicc@chromium.org) with questions.
The custom elements implementation is split between core/dom and bindings/core/v8.
The definition of one ‘class’ of element. This type is abstract to permit different kinds of definitions, although at the moment there is only one: ScriptCustomElementDefinition.
ScriptCustomElementDefinition is linked to its constructor by an ID number. The ID number is stored in a map, keyed by constructor, in a hidden value of the CustomElementRegistry wrapper. The ID is an index into a list of definitions stored in V8PerContextData.
A tuple of local name, and custom element name. For autonomous custom elements, these strings are the same; for customized built-in elements these strings will be different. In that case, the local name is the element's tag name and the custom element name is related to the value of the “is” attribute.
Implements the window.customElements
property. This maintains the set of registered names. The wrapper of this object is used by ScriptCustomElementDefinition to cache state in V8.
The HTMLElement
interface constructor. When a custom element is created from JavaScript all we have to go on is the constructor (in new.target
); this uses ScriptCustomElementDefinition's state to find the definition to use.
Once defined, custom element constructors and prototypes have to be kept around indefinitely because they could be created in future by the parser. On the other hand, we must not leak when a window can no longer run script.
We use a V8HiddenValue on the CustomElementRegistry wrapper which points to a map that keeps constructors and prototypes alive. See ScriptCustomElementDefinition.
In comments and prose, write custom elements, not Custom Elements, to match the HTML standard.
Prefix type names with CustomElement (singular).
Custom elements have small C++ unit tests and medium “layout” tests.
These are in third_party/blink/renderer/core/dom/*_test.cc and are built as part of the webkit_unit_tests target. The test names start with CustomElement so you can run them with:
$ out/Debug/webkit_unit_tests --gtest_filter=CustomElement*
The custom element layout tests are generally in third_party/blink/web_tests/custom-elements.
All custom elements layout tests use the web-platform-tests harness and follow its style. The WPT style is not very prescriptive, so be consistent with other custom elements tests.
When naming tests, use short names describing what the test is doing. Avoid articles. For example, “HTMLElement constructor, invoke”. When writing assertion messages, start with a lowercase letter (unless the word is a proper noun), use normal grammar and articles, and include the word “should” to leave no doubt whate the expected behavior is.
These will be upstreamed to WPT, replacing the tests for registerElement we contributed earlier. To facilitate that, follow these guidelines:
spec
directory.window.internals
for example.These are for testing Blink-specific details like object lifetimes, crash regressions, interaction with registerElement and HTML Imports, and so on.
These tests can use Blink-specific testing hooks like window.internals
and testRunner
.
Finally there are /TODO(dominicc): should be/ tests in webexposed/custom-elements which assert that we HAVE NOT shipped window.customElements.define
yet. These tests need to be updated when we ship window.customElements.define
or remove registerElement
.
The plan is to:
window.customElements.define
, add a deprecation warning to document.registerElement
directing authors to use the new API.These have links to the parts of the DOM and HTML specs which define custom elements: