This specification describes the method for enabling the author to define and use new types of DOM elements in a document. It will eventually be upstreamed into [[!WHATWG-DOM]], [[!HTML]], and [[!WEBIDL]]. Sections which explicitly modify existing parts of these specifications are denoted with "DOM+", "HTML+", or "Web IDL+" in their titles.
Any point, at which a conforming UA must make decisions about the state or reaction to the state of the conceptual model, is captured as algorithm. The algorithms are defined in terms of processing equivalence. The processing equivalence is a constraint imposed on the algorithm implementors, requiring the output of the both UA-implemented and the specified algorithm to be exactly the same for all inputs.
The IDL fragments in this specification must be interpreted as required for conforming IDL fragments, as described in the Web IDL specification [[!WEBIDL]].
This section should be inserted into the section The elements of HTML, probably as a subsection following "Scripting" and before "Common idioms without dedicated elements".
Custom elements provide a way for authors to build their own fully-featured DOM elements. Although authors could always use non-standard tag names in their documents, with application-specific behavior added after the fact by scripting or similar, such elements have historically been non-conforming and not very functional. By defining a custom element, authors can inform the parser how to properly construct an element and how elements of that class should react to changes.
Custom elements are part of a larger effort to "rationalize the platform," by explaining existing platform features (like the elements of HTML) in terms of lower-level author-exposed extensibility points (like custom element definition). Although today there are many limitations on the capabilities of custom elements—both functionally and semantically—that prevent them from fully explaining the behaviors of HTML's existing elements, we hope to shrink this gap over time.
For the purposes of illustrating how to create a custom tag, let's define a custom element that encapsulates rendering a small icon for a country flag. Our goal is to be able to use it like so:
<flag-icon country="nl"></flag-icon>
To do this, we first declare a class for the custom element, extending HTMLElement
:
class FlagIcon extends HTMLElement { constructor() { super() this._countryCode = null } static get observedAttributes() { return ["country"]; } attributeChangedCallback(name, oldValue, newValue) { // name will always be "country" due to observedAttributes this._countryCode = newValue this._updateRendering() } connectedCallback() { this._updateRendering() } get country() { return this._countryCode } set country(v) { this.setAttribute("country", v) } _updateRendering() { // Left as an exercise for the reader. But, you'll probably want to // check this.ownerDocument.defaultView to see if we've been // inserted into a document with a browsing context, and avoid // doing any work if not. } }
We then need to use this class to define the element:
customElements.define("flag-icon", FlagIcon);
At this point, our above code will work! The parser, whenever it sees the flag-icon
tag, will construct a new instance of our FlagIcon
class, and tell our code about its new country
attribute, which we then use to set the element's internal state and update its rendering (when appropriate).
You can also create flag-icon
elements directly, using the DOM API:
const flagIcon = document.createElement("flag-icon") flagIcon.country = "jp" document.body.appendChild(flagIcon)
Finally, we can also use the custom element constructor itself. That is, the above code is equivalent to:
const flagIcon = new FlagIcon() flagIcon.country = "jp" document.body.appendChild(flagIcon)
Type extensions are a distinct kind of custom element, which are defined slightly differently and used very differently. They exist to allow reuse of behaviors from the existing elements of HTML, by extending those elements with new custom functionality. This is important since many of the existing behaviors of HTML elements can unfortunately not be duplicated by using purely custom tags. Instead, type extensions allow the installation of custom construction behavior, lifecycle hooks, and prototype chain onto onto existing elements, essentially "mixing in" these capabilities on top of the already-existing element.
Type extensions require a distinct syntax from custom tags because user agents and other software key off an element's local name in order to identify the element's basic nature. That is, the concept of type extensions building on top of existing behavior depends crucially on the extended elements retaining their original local name.
In this example, we'll be creating a type extension named plastic-button
, which behaves like a normal button but gets fancy animation effects added whenever you click on it. We start by defining a class, just like before, although this time we extend HTMLButtonElement
instead of HTMLElement
:
class PlasticButton extends HTMLButtonElement { constructor() { super() this.addEventListener("click", () => { // Draw some fancy animation effects! }) } }
When defining our custom element, we have to also specify the extends
option:
customElements.define("plastic-button", PlasticButton, { extends: "button" });
In general, the name of the element being extended cannot be determined simply by looking at what element interface it extends, as many elements share the same interface (such as q
and blockquote
both sharing HTMLQuoteElement
).
To use our type extension, we use the is
attribute on a button
element:
<button is="plastic-button">Click Me!</button>
Trying to use a type extension as a custom tag will not work; that is, <plastic-button>Click me?</plastic-button>
will simply create a HTMLUnknownElement
with no special behavior.
If you need to create a type extension programmatically, you can use the following form of createElement
:
const plasticButton = document.createElement("button", { is: "plastic-button" }) plasticButton.textContent = "Click me!"
And as before, the constructor will also work:
const plasticButton2 = new PlasticButton() console.log(plasticButton2.localName); // will output "button" console.log(plasticButton2.getAttribute("is")); // will output "plastic-button"
Notably, all the of the ways in which button
is special apply to such "plastic buttons" as well: their focus behavior, ability to participate in form submission, the disabled
attribute, and so on.
As specified below, and alluded to above, simply defining and using an element called taco-button
does not mean that such elements represent buttons. That is, tools such as Web browsers, search engines, or accessibility technology will not automatically treat the resulting element as a button just based on its defined name.
To convey the desired button semantics to a variety of users, while still using a custom tag, a number of techniques would need to be employed:
tabindex
attribute would make the taco-button
interactive content, thus making it focusable. Note that if the taco-button
were to become logically disabled, the tabindex
attribute would need to be removed.role
attribute to button
will convey the semantics that this is a button, enabling users to successfully interact with the control using usual button-like interactions in their accessibility technology. Setting the aria-label
attribute is necessary to give the button an accessible name, instead of having accessibility technology traverse its child text nodes and announce them. And setting aria-disabled
to "true
" when the button is logically disabled conveys to accessibility technology the button's disabled state.keydown
events to become click
events, so that you can activate the button both with keyboard and by clicking.taco-button
elements, the visual styling will also need to be updated to reflect changes in logical state, such as becoming disabled; that is, whatever stylesheet has rules for taco-button
will also need to have rules for taco-button[disabled]
.With these points in mind, a full-featured taco-button
that took on the responsibility of conveying button semantics (including the ability to be disabled) might look something like this:
class TacoButton extends HTMLElement { static get observedAttributes() { return ["disabled"]; } constructor() { super(); this.addEventListener("keydown", e => { if (e.keyCode === 32 || e.keyCode === 13) { this.dispatchEvent(new MouseEvent("click", { bubbles: true, cancelable: true })); } }); this.addEventListener("click", e => { if (this.disabled) { e.preventDefault(); e.stopPropagation(); } }); this._observer = new MutationObserver(() => { this.setAttribute("aria-label", this.textContent); }); } attachedCallback() { this.setAttribute("role", "button"); this.setAttribute("tabindex", "0"); this._observer.observe(this, { childList: true, characterData: true, subtree: true }); } disconnectedCallback() { this._observer.disconnect(); } get disabled() { return this.hasAttribute("disabled"); } set disabled(v) { if (v) { this.setAttribute("disabled", ""); } else { this.removeAttribute("disabled"); } } attributeChangedCallback() { // only is called for the disabled attribute due to observedAttributes if (this.disabled) { this.setAttribute("tabindex", "-1"); this.setAttribute("aria-disabled", "true"); } else { this.setAttribute("tabindex", "0"); this.setAttribute("aria-disabled", "false"); } } }
Even with this rather-complicated element definition, the element is not a pleasure to use for consumers: it will be continually "sprouting" tabindex
and aria-*
attributes of its own volition. This is because as of now there is no way to specify default accessibility semantics or focus behavior for custom elements, forcing the use of these attributes to do so (even though they are usually reserved for allowing the consumer to override default behavior).
In contrast, a simple type extension, as shown in the previous section, would automatically inherit the semantics and behavior of the button
element, with no need to implement these behaviors manually. In general, for any element with nontrivial behavior and semantics which builds on top of existing elements of HTML, type extensions will be easier to develop, maintain, and consume.
Because element definition can occur at any time, a non-custom element could be created, and then later become a custom element after an appropriate definition is registered. We call this process "upgrading" the element, from a normal element into a custom element.
Upgrades enable scenarios where it may be preferable for custom element definitions to be registered after relevant elements has been initially created, such as by the parser. They allow progressive enhancement of the content in the custom element. For example, in the following HTML document the element definition for img-viewer
is loaded asynchronously:
<!DOCTYPE html> <title>Image viewer example</title> <img-viewer filter="Kelvin"> <img src="images/tree.jpg" alt="A beautiful tree towering over an empty savannah"> </img-viewer> <script src="js/elements/img-viewer.js" async></script>
The definition for the img-viewer
element here is loaded using a script
element marked with the async
attribute, placed after the <img-viewer>
tag in the markup. While the script is loading, the img-viewer
element will be treated as an undefined element, similar to a span
. Once the script loads, it will define the img-viewer
element, and the existing img-viewer
element on the page will be upgraded, applying the custom element's definition (which presumably includes applying an image filter identified by the string "Kelvin", enhancing the image's visual appearance).
Note that upgrades only apply to elements in the document tree. (Formally, elements in a shadow-including document.) An element that is not inserted into a document will stay un-upgraded. An example illustrates this point:
<!DOCTYPE html> <title>Upgrade edge-cases example</title> <example-element></example-element> <script> "use strict"; const inDocument = document.querySelector("example-element"); const outOfDocument = document.createElement("example-element"); // Before the element definition, both are HTMLElement: console.assert(inDocument instanceof HTMLElement); console.assert(outOfDocument instanceof HTMLElement); class ExampleElement extends HTMLElement {} customElements.define("example-element", ExampleElement); // After element definition, the in-document element was upgraded: console.assert(inDocument instanceof ExampleElement); console.assert(!(outOfDocument instanceof ExampleElement)); document.body.appendChild(outOfDocument); // Now that we've moved the element into the document, it too was upgraded: console.assert(outOfDocument instanceof ExampleElement); </script>
When authoring custom element constructors, authors are bound by the following conformance requirements:
super()
must be the first statement in the constructor body, to establish the correct prototype chain and this
value before any further code is run.return
statement must not appear anywhere inside the constructor body, unless it is a simple early-return (return
or return this
).createElement
or createElementNS
methods.connectedCallback
as much as possible—especially work involving fetching resources or rendering. However, note that connectedCallback
can be called more than once, so any initialization work that is truly one-time will need a guard to prevent it from running twice.Several of these requirements are checked during element creation, either directly or indirectly, and failing to follow them will result in a custom element that cannot be instantiated by the parser or DOM APIs.
A custom element is an element that is custom. Informally, this means that its constructor and prototype are defined by the author, instead of by the user agent. This author-supplied constructor function is called the custom element constructor.
Two distinct types of custom elements can be defined:
extends
option. These types of custom elements have local name equal to their defined name.extends
option. These types of custom elements have local name equal to the value passed in their extends
option, and their defined name is used as the value of the is
attribute.After a custom element is created, changing the value of the is
attribute does not change the element's behavior.
Custom tags have the following element definition:
HTMLElement
).A custom tag does not have any special meaning: it represents its children. A type extension inherits the semantics of the element that it extends.
A valid custom element name is a sequence of characters name that meets all of the following requirements:
name must match the PotentialCustomElementName
production:
PotentialCustomElementName ::=
[a-z] (PCENChar)* '-' (PCENChar)*
PCENChar ::=
"-" | "." | [0-9] | "_" | [a-z] | #xB7 | [#xC0-#xD6] | [#xD8-#xF6] | [#xF8-#x2FF] | [#x300-#x37D] | [#x37F-#x1FFF] | [#x200C-#x200D] | [#x203F-#x2040] | [#x2070-#x218F] | [#x2C00-#x2FEF] | [#x3001-#xD7FF] | [#xF900-#xFDCF] | [#xFDF0-#xFFFD] | [#x10000-#xEFFFF]
This uses the EBNF notation from the XML specification. [[!XML]]
name must not be any of the following:
annotation-xml
color-profile
font-face
font-face-src
font-face-uri
font-face-format
font-face-name
missing-glyph
The list of names above is the summary of all hyphen-containing element names from the applicable specifications, namely SVG and MathML. [[SVG11]] [[MathML]]
These requirements ensure a number of goals for valid custom element names:
document.createElement
and document.createElementNS
, which have restrictions that go beyond the parser's.Apart from these restrictions, a large variety of names is allowed, to give maximum flexibility for use cases like <math-α>
or <emotion-😍>
.
A custom element definition describes a custom element and consists of:
sequence<DOMString>
; Each custom element definition's construction stack is manipulated by the upgrade an element algorithm and the HTMLElement
constructor. Each entry in the list will be either an element or an already constructed marker.
Each custom element definition's lifecycle callbacks is a map, whose three keys are the strings "connectedCallback
", "disconnectedCallback
", and "attributeChangedCallback
". The corresponding values are either a JavaScript function object, or undefined. By default the value of each entry is undefined.
To look up a custom element definition, given a document, namespace, localName, and is, perform the following steps. They will return either a custom element definition or null:
Window
's CustomElementsRegistry
object.CustomElementsRegistry
interfaceEach Window
object is associated with a unique instance of a CustomElementsRegistry
object, allocated when the Window
object is created.
Custom element registries are associated with Window
objects, instead of Document
objects, since each custom element constructor inherits from the HTMLElement
interface, and there is exactly one HTMLElement
interface per Window
object.
The customElements
attribute of the Window
interface must return the CustomElementsRegistry
object for that Window
object.
interface CustomElementsRegistry { void define(DOMString name, Function constructor, optional ElementRegistrationOptions options); }; dictionary ElementRegistrationOptions { DOMString extends; };
customElements
. define
(name, constructor)customElements
. define
(name, constructor, { extends: baseTagName })NotSupportedError
will be thrown upon trying to extend a custom element or an unknown element.Every CustomElementsRegistry
has a set of custom element definitions, initially empty. In general, algorithms in this specification look up elements in the registry by any of name, local name, or constructor.
A CustomElementsRegistry
's list of defined local names is the list containing all of the local names of the custom element definitions in the registry.
Element definition is a process of adding a custom element definition to the CustomElementsRegistry
. This is accomplished by the define
method. When invoked, the define(name, constructor, options)
method must run these steps:
TypeError
and abort these steps.SyntaxError
and abort these steps.CustomElementsRegistry
contains an entry with name name, throw a NotSupportedError
and abort these steps.CustomElementsRegistry
contains an entry with constructor constructor, throw a NotSupportedError
and abort these steps.extends
member of options, or null if no such member exists.If extends is not null:
HTMLUnknownElement
, throw a NotSupportedError
and abort these steps.sequence<DOMString>
. Otherwise, let observedAttributes be the result of converting observedAttributesIterable to a sequence<DOMString>
. Rethrow any exceptions.TypeError
exception.TypeError
exception.TypeError
exception.TypeError
exception.CustomElementsRegistry
.To upgrade an element, given as input a custom element definition definition and an element element, run the following steps:
If SameValue(constructResult.[[\value]], element) is false, throw a InvalidStateError
and terminate these steps.
This can occur if C constructs another instance of the same custom element before calling super()
, or if C uses JavaScript's return
-override feature to return an arbitrary object from the constructor.
customized
".attributeChangedCallback
", and an argument list containing attribute's local name, null, attribute's value, and attribute's namespace.connectedCallback
", and an empty argument list.To try to upgrade an element, given as input an element element, run the following steps:
is
", if any such attribute exists, or null otherwise.A custom element possesses the ability to respond to certain occurrences by running author code:
connectedCallback
is run.disconnectedCallback
is run.attributeChangedCallback
is run.We call these reactions collectively custom element reactions.
The way in which custom element reactions are invoked is done with special care, to avoid running author code during the middle of delicate operations. Effectively, they are delayed until "just before returning to user script". This means that for most purposes they appear to execute synchronously, but in the case of complicated composite operations (like cloning, or range manipulation), they will instead be delayed until after all the relevant user agent processing steps have completed, and then run together as a batch.
Additionally, the precise ordering of these reactions is managed via a somewhat-complicated stack-of-queues system, described below. The intention behind this system is to guarantee that custom element reactions always are invoked in the same order as their triggering actions, at least within the local context of a single custom element. (Because custom element reaction code can perform its own mutations, it is not possible to give a global ordering guarantee across multiple elements.)
Each unit of related similar-origin browsing contexts has a custom element reactions stack, which is initially empty. Each item in the stack is an element queue, which is initially empty as well; the element queue at the top of the stack is called the current element queue. Each item in an element queue is an element. (The elements are not necessarily custom yet, since this queue is used for upgrades as well.)
All elements have an associated custom element reaction queue, initially empty. Each item in the custom element reaction queue is of one of two types:
This is all summarized in the following schematic diagram:
To enqueue a custom element callback reaction, given a custom element element, a callback name callbackName, and a list of arguments args, run the following steps:
Window
's CustomElementsRegistry
object.This algorithm can only be called when such a definition exists.
If callbackName is "attributeChangedCallback
":
To enqueue a custom element upgrade reaction, given an element element and custom element definition definition, run the following steps:
To invoke custom element reactions in an element queue queue, run the following steps:
For each custom element element in queue:
Repeat until reactions is empty:
Remove the first element of reactions, and let reaction be that element. Switch on reaction's type:
If this throws any exception, report the exception.
The following needs to be formalized more; see #186.
Any time a script calls a method, reads or sets a property that is implemented by the user agent, the following actions MUST occur:
Window
objectHTML's Window
object definition must be extended as follows:
partial interface Window { readonly attribute CustomElementsRegistry customElements; };
As is conventional for HTML, the actual definition of this property is elsewhere in the specification (cf. location
and history
). We have it above in the section "The CustomElementsRegistry
interface".
HTML currently does not do a great job of defining DOM's element interface concept. There is a definition hidden inside the parser, but it isn't explicit that this also covers other element creation cases. We should create a section that is more explicit, and it should roughly contain the following (including the note afterward):
The element interface for an element with name name in the HTML namespace is determined as follows:
HTMLElement
.HTMLUnknownElement
.
The use of HTMLElement
instead of HTMLUnknownElement
in the case of valid custom element names is done to ensure that any potential future upgrades only cause a linear transition of the element's prototype chain, from HTMLElement
to a subclass, instead of a lateral one, from HTMLUnknownElement
to an unrelated subclass.
The following should be added to HTML's pseudo-classes section.
:defined
:defined
pseudo-class must match any element that is defined.HTMLElement
constructorThe HTMLElement
interface gains following annotation:
[Constructor]
We then add the following definition:
TheHTMLElement
constructor, when invoked, must perform the following steps:
HTMLElement
function).CustomElementsRegistry
object.TypeError
and abort these steps.If definition's construction stack is empty, perform the following substeps:
HTMLElement
, with no attributes, namespace set to the HTML namespace, local name set to localName, and node document set to document.This occurs when author script constructs a new custom element directly, e.g. via new MyCustomElement()
.
If instance is an already constructed marker, throw an InvalidStateError
and abort these steps.
This can occur when the author code inside the custom element constructor invokes super()
multiple times.
Return instance.
This step is normally reached when upgrading a custom element; the existing element is returned, so that the super()
call inside the custom element constructor assigns that existing element to this
.
For now, the HTMLElement
constructor cannot be invoked directly. It only works when used via a super()
call inside a custom element constructor.
The create an element for a token algorithm should be adjusted by replacing step 1 with the following steps, and adjusting further steps to refer to element instead of "the element" or "the newly created element".
is
" attribute in the given token, if such an attribute exists, or null otherwise.If will execute script is true:
Let element be the result of creating an element given document, localName, null, given namespace, and is. If will execute script is true, set the synchronous custom elements flag; otherwise, leave it unset.
This will cause custom element constructors to run, if will execute script is true. However, even if this causes new characters to be inserted into the tokenizer, the parser will not be executed reentrantly, since the parser pause flag is true. Similarly, blowing away the document is not possible, since the script nesting level is greater than zero.
If this step throws an exception, report the exception, and let element be instead a new element that implements HTMLUnknownElement
, with no attributes, namespace set to given namespace, namespace prefix set to null, custom element state "undefined
", and node document set to document.
Append each attribute in the given token to element.
This can enqueue a custom element callback reaction for the attributeChangedCallback
, which might run immediately (in the next step).
Even though the "is
" attribute governs the creation of a type extension, it is not present during the execution of the relevant custom element constructor; it is appended in this step, along with all other attributes.
If will execute script is true:
It turns out there's not actually a spec for the XML parser. Awesome! (Not actually awesome.) The HTML Standard has a nice vague paragraph about "This Document
must then be populated with DOM nodes that represent the tree structure of the input passed..." which should get something like the following inserted (probably by inserting it after the first sentence, then splitting the mutation events/observers prose into a new paragraph).
When creating DOM nodes representing elements, the create an element for a token algorithm or some equivalent that operates on appropriate XML datastructures must be used, to ensure the proper element interfaces are created and that custom elements are set up correctly.
HTML has several sections that need to be updated when introducing a new element, or in this case class of elements. Those are:
The Element
interface section will need to be modified as follows. The paragraph listing the values associated with an element should be modified to read as follows, including the note afterward:
Elements have an associated namespace, namespace prefix, local name, and custom element state. When an element is created, all of these values are initialized.
An element's custom element state is one of "undefined
", "uncustomized
", or "custom
". An element whose custom element state is either "uncustomized
" or "custom
" is said to be defined. An element whose custom element state is "custom
" is said to be custom.
Whether or not an element is defined is used to determine the behavior of the :defined
pseudo-class. Whether or not an element is custom is used to determine the behavior of the mutation algorithms.
The following code illustrates elements in each of these three states:
<!DOCTYPE html> <script> window.customElements.define("sw-rey", class extends HTMLElement {}) window.customElements.define("sw-finn", class extends HTMLElement {}, { extends: "p" }) window.customElements.define("sw-kylo", class extends HTMLElement { constructor() { super() throw new Error("The droid... stole a freighter?") } }) </script> <!-- "undefined" (not defined, not custom) --> <sw-han></sw-han> <sw-kylo></sw-kylo> <p is="sw-luke"></p> <p is="asdf"></p> <!-- "uncustomized" (defined, not custom) --> <p></p> <asdf></asdf> <!-- "custom" (defined, custom) --> <sw-rey></sw-rey> <p is="sw-finn"></p>
Additionally, after the talk about qualified names but before the discussion of attributes, the following algorithm should be inserted:
To create an element, given a document, prefix, localName, namespace, is, and optional synchronous custom elements flag, run the following steps:
If definition is non-null, and definition's name is not equal to its local name (i.e. definition represents a type extension), then:
undefined
", and node document set to document.Otherwise, if definition is non-null, then:
If synchronous custom elements flag is set:
If result does not implement the HTMLElement
interface, throw a TypeError
exception.
This is meant to be a brand check to ensure that the object was allocated by the HTMLElement
constructor. Eventually Web IDL may give us a more precise way to do brand checks.
TypeError
exception.NotSupportedError
exception.NotSupportedError
exception.NotSupportedError
exception.NotSupportedError
exception.NotSupportedError
exception.NotSupportedError
exception.custom
".Otherwise:
HTMLElement
interface, with no attributes, namespace set to the HTML namespace, namespace prefix set to prefix, local name set to localName, custom element state "undefined
", and node document set document.Otherwise:
uncustomized
", and node document set to document.undefined
".The clone a node algorithm will need to be modified as follows. A new case, separate from the main switch, will be needed to generate copy for Element
s. It should use create an element, given document, node's local name, node's namespace prefix, node's namespace, and the value of node's is
attribute (if present). The synchronous custom elements flag should be unset.
The mutation algorithms sections need to be modified as follows to properly enqueue custom element callbacks.
Modify the insert algorithm as follows. Replace step 6.2 with:
For each shadow-including inclusive descendant inclusiveDescendant of node, in shadow-including tree order, run these subsubsteps:
If inclusiveDescendant is in a shadow-including document, then:
connectedCallback
", and an empty argument list.Otherwise, try to upgrade inclusiveDescendant.
If this successfully upgrades inclusiveDescendant, its connectedCallback
will be enqueued automatically during the upgrade an element algorithm.
Modify the remove algorithm as follows. Replace step 9 with:
For each shadow-including inclusive descendant inclusiveDescendant of node, in shadow-including tree order, run these subsubsteps:
disconnectedCallback
", and an empty argument list.Modify the change an attribute algorithm as follows. Add an additional step after step 1:
attributeChangedCallback
", and an argument list containing attribute's local name, attribute's value, value, and attribute's namespace.Modify the append an attribute algorithm as follows. Add an additional step after step 1:
attributeChangedCallback
", and an argument list containing attribute's local name, null, attribute's value, and attribute's namespace.Modify the remove an attribute algorithm as follows. Add an additional step after step 1:
attributeChangedCallback
", and an argument list containing attribute's local name, attribute's value, null, and attribute's namespace.Modify the replace an attribute algorithm as follows. Add an additional step after step 1:
attributeChangedCallback
", and an argument list containing oldAttr's local name, oldAttr's value, newAttr's value, and oldAttr's namespace.Document
methodsTo allow creating both custom tag and type extension-style custom elements, the createElement
or createElementNS
methods gain optional typeExtension arguments. Their new definitions are:
partial interface Document { Element createElement(DOMString localName, optional ElementCreationOptions options); Element createElementNS(DOMString? namespace, DOMString qualifiedName, optional ElementCreationOptions options); }; dictionary ElementCreationOptions { DOMString is; };
createElement(localName, options)
method, when invoked, must run these steps:
Name
production, throw an InvalidCharacterError
exception.is
member of options, or null if no such member exists.NotFoundError
.is
" and is.createElementNS(namespace, qualifiedName, options)
method, when invoked, must run these steps:
is
member of options, or null if no such member exists.NotFoundError
.is
" and is.David Hyatt developed XBL 1.0, and Ian Hickson co-wrote XBL 2.0. These documents provided tremendous insight into the problem of behavior attachment and greatly influenced this specification.
Alex Russell and his considerable forethought triggered a new wave of enthusiasm around the subject of behavior attachment and how it can be applied practically on the Web.
Dominic Cooney, Hajime Morrita, and Roland Steiner worked tirelessly to scope the problem within the confines of the Web platform and provided a solid foundation for this document.
Steve Faulkner, The Paciello Group, for writing the content of the section .
The <flag-icon> example was inspired by a custom element by Steven Skelton. (MIT)
The editor would also like to thank Alex Komoroske, Andres Rios, Anne van Kesteren, Boris Zbarsky, Daniel Buchner, Edward O'Connor, Erik Arvidsson, Elliott Sprehn, Hayato Ito, Jan Miksovsky, Jonas Sicking, Olli Pettay, Rafael Weinstein, Ryosuke Niwa, Scott Miles, Simon Pieters, Steve Orvell, Tab Atkins, Tim Perry, and William Chen for their comments and contributions to this specification.
This list is too short. There's a lot of work left to do. Please contribute by reviewing and filing bugs—and don't forget to ask the editor to add your name into this section.