Living Standard — Last Updated 7 March 2021
CustomElementRegistry
interface
Support in all current engines.
This section is non-normative.
Custom elements provide a way for authors to build their own fully-featured DOM elements. Although authors could always use non-standard elements 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 "rationalise 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.
This section is non-normative.
For the purposes of illustrating how to create an autonomous custom element , 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
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)
This section is non-normative.
Adding
a
static
formAssociated
property,
with
a
true
value,
makes
an
autonomous
custom
element
a
form-associated
custom
element
.
The
ElementInternals
interface
helps
you
to
implement
functions
and
properties
common
to
form
control
elements.
class MyCheckbox extends HTMLElement {
static get formAssociated() { return true; }
static get observedAttributes() { return ['checked']; }
constructor() {
super();
this._internals = this.attachInternals();
this.addEventListener('click', this._onClick.bind(this));
}
get form() { return this._internals.form; }
get name() { return this.getAttribute('name'); }
get type() { return this.localName; }
get checked() { return this.getAttribute('checked'); }
set checked(flag) { this.toggleAttribute('checked', Boolean(flag)); }
attributeChangedCallback(name, oldValue, newValue) {
// name will always be "checked" due to observedAttributes
this._internals.setFormValue(this.checked ? 'on' : null);
}
_onClick(event) {
this.checked = !this.checked;
}
}
customElements.define('my-checkbox',
MyCheckbox);
You
can
use
the
custom
element
my-checkbox
like
a
built-in
form-associated
element.
For
example,
putting
it
in
form
or
label
associates
the
my-checkbox
element
with
them,
and
submitting
the
form
will
send
data
provided
by
my-checkbox
implementation.
<form action="..." method="...">
<label><my-checkbox name="agreed"></my-checkbox> I read the agreement.</label>
<input type="submit">
</form>
This section is non-normative.
By
using
the
appropriate
properties
of
ElementInternals
,
your
custom
element
can
have
default
accessibility
semantics.
The
following
code
expands
our
form-associated
checkbox
from
the
previous
section
to
properly
set
its
default
role
and
checkedness,
as
viewed
by
accessibility
technology:
class MyCheckbox extends HTMLElement {
static get formAssociated() { return true; }
static get observedAttributes() { return ['checked']; }
constructor() {
super();
this._internals = this.attachInternals();
this.addEventListener('click', this._onClick.bind(this));
this._internals.role = 'checkbox';
this._internals.ariaChecked = false;
}
get form() { return this._internals.form; }
get name() { return this.getAttribute('name'); }
get type() { return this.localName; }
get checked() { return this.getAttribute('checked'); }
set checked(flag) { this.toggleAttribute('checked', Boolean(flag)); }
attributeChangedCallback(name, oldValue, newValue) {
// name will always be "checked" due to observedAttributes
this._internals.setFormValue(this.checked ? 'on' : null);
this._internals.ariaChecked = this.checked;
}
_onClick(event) {
this.checked = !this.checked;
}
}
customElements.define('my-checkbox',
MyCheckbox);
Note
that,
like
for
built-in
elements,
these
are
only
defaults,
and
can
be
overridden
by
the
page
author
using
the
role
and
aria-*
attributes:
<!-- This markup is non-conforming -->
<input
type="checkbox"
checked
role="button"
aria-checked="false">
<!-- This markup is probably not what the custom element author intended -->
<my-checkbox
role="button"
checked
aria-checked="false">
Custom
element
authors
are
encouraged
to
state
what
aspects
of
their
accessibility
semantics
are
strong
native
semantics,
i.e.,
should
not
be
overridden
by
users
of
the
custom
element.
In
our
example,
the
author
of
the
my-checkbox
element
would
state
that
its
role
and
aria-checked
values
are
strong
native
semantics,
thus
discouraging
code
such
as
the
above.
This section is non-normative.
Customized built-in elements are a distinct kind of custom element , which are defined slightly differently and used very differently compared to autonomous custom elements . 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 autonomous custom elements . Instead, customized built-in elements allow the installation of custom construction behavior, lifecycle hooks, and prototype chain onto existing elements, essentially "mixing in" these capabilities on top of the already-existing element.
Customized built-in elements require a distinct syntax from autonomous custom elements because user agents and other software key off an element's local name in order to identify the element's semantics and behavior. That is, the concept of customized built-in elements 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
customized
built-in
element
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
construct
our
customized
built-in
element
from
parsed
HTML
source
text,
we
use
the
is
attribute
on
a
button
element:
<button
is="plastic-button">Click
Me!</button>
Trying
to
use
a
customized
built-in
element
as
an
autonomous
custom
element
will
not
work;
that
is,
<plastic-button>Click
me?</plastic-button>
will
simply
create
an
HTMLElement
with
no
special
behavior.
If
you
need
to
create
a
customized
built-in
element
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.assert(plasticButton2 instanceof PlasticButton);
console.assert(plasticButton2
instanceof
HTMLButtonElement);
Note
that
when
creating
a
customized
built-in
element
programmatically,
the
is
attribute
will
not
be
present
in
the
DOM,
since
it
was
not
explicitly
set.
However,
it
will
be
added
to
the
output
when
serializing
:
console.assert(!plasticButton.hasAttribute("is"));
console.log(plasticButton.outerHTML);
//
will
output
'<button
is="plastic-button"></button>'
Regardless
of
how
it
is
created,
all
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.
Customized
built-in
elements
are
designed
to
allow
extension
of
existing
HTML
elements
that
have
useful
user-agent
supplied
behavior
or
APIs.
As
such,
they
can
only
extend
existing
HTML
elements
defined
in
this
specification,
and
cannot
extend
legacy
elements
such
as
bgsound
,
blink
,
isindex
,
keygen
,
multicol
,
nextid
,
or
spacer
that
have
been
defined
to
use
HTMLUnknownElement
as
their
element
interface
.
One
reason
for
this
requirement
is
future-compatibility:
if
a
customized
built-in
element
was
defined
that
extended
a
currently-unknown
element,
for
example
combobox
,
this
would
prevent
this
specification
from
defining
a
combobox
element
in
the
future,
as
consumers
of
the
derived
customized
built-in
element
would
have
come
to
depend
on
their
base
element
having
no
interesting
user-agent-supplied
behavior.
This section is non-normative.
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 an autonomous custom element , a number of techniques would need to be employed:
The
addition
of
the
tabindex
attribute
would
make
the
taco-button
focusable
.
Note
that
if
the
taco-button
were
to
become
logically
disabled,
the
tabindex
attribute
would
need
to
be
removed.
The
addition
of
an
ARIA
role
and
various
ARIA
states
and
properties
helps
convey
semantics
to
accessibility
technology.
For
example,
setting
the
role
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
property
is
necessary
to
give
the
button
an
accessible
name
,
instead
of
having
accessibility
technology
traverse
its
child
text
nodes
and
announce
them.
And
setting
the
aria-disabled
state
to
"
true
"
when
the
button
is
logically
disabled
conveys
to
accessibility
technology
the
button's
disabled
state.
The
addition
of
event
handlers
to
handle
commonly-expected
button
behaviors
helps
convey
the
semantics
of
the
button
to
web
browser
users.
In
this
case,
the
most
relevant
event
handler
would
be
one
that
proxies
appropriate
keydown
events
to
become
click
events,
so
that
you
can
activate
the
button
both
with
keyboard
and
by
clicking.
In
addition
to
any
default
visual
styling
provided
for
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
style
sheet
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._internals = this.attachInternals();
this._internals.role = "button";
this.addEventListener("keydown", e => {
if (e.code === "Enter" || e.code === "Space") {
this.dispatchEvent(new PointerEvent("click", {
bubbles: true,
cancelable: true
}));
}
});
this.addEventListener("click", e => {
if (this.disabled) {
e.preventDefault();
e.stopImmediatePropagation();
}
});
this._observer = new MutationObserver(() => {
this._internals.ariaLabel = this.textContent;
});
}
connectedCallback() {
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(flag) {
this.toggleAttribute("disabled", Boolean(flag));
}
attributeChangedCallback(name, oldValue, newValue) {
// name will always be "disabled" due to observedAttributes
if (this.disabled) {
this.removeAttribute("tabindex");
this._internals.ariaDisabled = "true";
} else {
this.setAttribute("tabindex", "0");
this._internals.ariaDisabled = "false";
}
}
}
Even
with
this
rather-complicated
element
definition,
the
element
is
not
a
pleasure
to
use
for
consumers:
it
will
be
continually
"sprouting"
tabindex
attributes
of
its
own
volition,
and
its
choice
of
tabindex="0"
focusability
behavior
may
not
match
the
button
behavior
on
the
current
platform.
This
is
because
as
of
now
there
is
no
way
to
specify
default
focus
behavior
for
custom
elements,
forcing
the
use
of
the
tabindex
attribute
to
do
so
(even
though
it
is
usually
reserved
for
allowing
the
consumer
to
override
default
behavior).
In
contrast,
a
simple
customized
built-in
element
,
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
elements
with
nontrivial
behavior
and
semantics
that
build
on
top
of
existing
elements
of
HTML,
customized
built-in
elements
will
be
easier
to
develop,
maintain,
and
consume.
This section is non-normative.
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
have
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>
<html lang="en">
<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 that are connected .) An element that is not inserted into a document will stay un-upgraded. An example illustrates this point:
<!DOCTYPE html>
<html lang="en">
<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:
A
parameter-less
call
to
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.
A
return
statement
must
not
appear
anywhere
inside
the
constructor
body,
unless
it
is
a
simple
early-return
(
return
or
return
this
).
The
constructor
must
not
use
the
document.write()
or
document.open()
methods.
The element's attributes and children must not be inspected, as in the non- upgrade case none will be present, and relying on upgrades makes the element less usable.
The
element
must
not
gain
any
attributes
or
children,
as
this
violates
the
expectations
of
consumers
who
use
the
createElement
or
createElementNS
methods.
In
general,
work
should
be
deferred
to
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.
In general, the constructor should be used to set up initial state and default values, and to set up event listeners and possibly a shadow root .
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. This is true even if the work is done inside a constructor-initiated microtask , as a microtask checkpoint can occur immediately after construction.
When authoring custom element reactions , authors should avoid manipulating the node tree as this can lead to unexpected results.
An
element's
connectedCallback
can
be
queued
before
the
element
is
disconnected,
but
as
the
callback
queue
is
still
processed,
it
results
in
a
connectedCallback
for
an
element
that
is
no
longer
connected:
class CParent extends HTMLElement {
connectedCallback() {
this.firstChild.remove();
}
}
customElements.define("c-parent", CParent);
class CChild extends HTMLElement {
connectedCallback() {
console.log("CChild connectedCallback: isConnected =", this.isConnected);
}
}
customElements.define("c-child", CChild);
const parent = new CParent(),
child = new CChild();
parent.append(child);
document.body.append(parent);
// Logs:
//
CChild
connectedCallback:
isConnected
=
false
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:
An
autonomous
custom
element
,
which
is
defined
with
no
extends
option.
These
types
of
custom
elements
have
a
local
name
equal
to
their
defined
name
.
A
customized
built-in
element
,
which
is
defined
with
an
extends
option.
These
types
of
custom
elements
have
a
local
name
equal
to
the
value
passed
in
their
extends
option,
and
their
defined
name
is
used
as
the
value
of
the
is
attribute,
which
therefore
must
be
a
valid
custom
element
name
.
After
a
custom
element
is
created
,
changing
the
value
of
the
is
attribute
does
not
change
the
element's
behavior,
as
it
is
saved
on
the
element
as
its
is
value
.
Autonomous custom elements have the following element definition:
is
attribute
form
,
for
form-associated
custom
elements
disabled
,
for
form-associated
custom
elements
readonly
,
for
form-associated
custom
elements
name
,
for
form-associated
custom
elements
HTMLElement
)
An autonomous custom element does not have any special meaning: it represents its children. A customized built-in element inherits the semantics of the element that it extends.
Any
namespace-less
attribute
that
is
relevant
to
the
element's
functioning,
as
determined
by
the
element's
author,
may
be
specified
on
an
autonomous
custom
element
,
so
long
as
the
attribute
name
is
XML-compatible
and
contains
no
ASCII
upper
alphas
.
The
exception
is
the
is
attribute,
which
must
not
be
specified
on
an
autonomous
custom
element
(and
which
will
have
no
effect
if
it
is).
Customized
built-in
elements
follow
the
normal
requirements
for
attributes,
based
on
the
elements
they
extend.
To
add
custom
attribute-based
behavior,
use
data-*
attributes.
An autonomous custom element is called a form-associated custom element if the element is associated with a custom element definition whose form-associated field is set to true.
The
name
attribute
represents
the
form-associated
custom
element
's
name.
The
disabled
attribute
is
used
to
make
the
form-associated
custom
element
non-interactive
and
to
prevent
its
submission
value
from
being
submitted.
The
form
attribute
is
used
to
explicitly
associate
the
form-associated
custom
element
with
its
form
owner
.
The
readonly
attribute
of
form-associated
custom
elements
specifies
that
the
element
is
barred
from
constraint
validation
.
User
agents
don't
provide
any
other
behavior
for
the
attribute,
but
custom
element
authors
should,
where
possible,
use
its
presence
to
make
their
control
non-editable
in
some
appropriate
fashion,
similar
to
the
behavior
for
the
readonly
attribute
on
built-in
form
controls.
Constraint
validation
:
If
the
readonly
attribute
is
specified
on
a
form-associated
custom
element
,
the
element
is
barred
from
constraint
validation
.
The
reset
algorithm
for
form-associated
custom
elements
is
to
enqueue
a
custom
element
callback
reaction
with
the
element,
callback
name
"
formResetCallback
",
and
an
empty
argument
list.
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-#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 2 and MathML . [SVG] [MATHML]
These requirements ensure a number of goals for valid custom element names :
They start with an ASCII lower alpha , ensuring that the HTML parser will treat them as tags instead of as text.
They do not contain any ASCII upper alphas , ensuring that the user agent can always treat HTML elements ASCII-case-insensitively.
They contain a hyphen, used for namespacing and to ensure forward compatibility (since no elements will be added to HTML, SVG, or MathML with hyphen-containing local names in the future).
They
can
always
be
created
with
createElement()
and
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:
CustomElementConstructor
callback
function
type
value
wrapping
the
custom
element
constructor
sequence<DOMString>
connectedCallback
",
"
disconnectedCallback
",
"
adoptedCallback
",
"
attributeChangedCallback
",
"
formAssociatedCallback
",
"
formDisabledCallback
",
"
formResetCallback
",
and
"
formStateRestoreCallback
".
The
corresponding
values
are
either
a
Web
IDL
Function
callback
function
type
value,
or
null.
By
default
the
value
of
each
entry
is
null.
attachInternals()
.
attachShadow()
.
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:
If namespace is not the HTML namespace , return null.
If document 's browsing context is null, return null.
Let
registry
be
document
's
relevant
global
object
's
CustomElementRegistry
object.
If there is custom element definition in registry with name and local name both equal to localName , return that custom element definition .
If there is a custom element definition in registry with name equal to is and local name equal to localName , return that custom element definition .
Return null.
CustomElementRegistry
interface
Each
Window
object
is
associated
with
a
unique
instance
of
a
CustomElementRegistry
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.
Support in all current engines.
The
customElements
attribute
of
the
Window
interface
must
return
the
CustomElementRegistry
object
for
that
Window
object.
Support in all current engines.
[Exposed=Window]
interface CustomElementRegistry {
[CEReactions] undefined define(DOMString name, CustomElementConstructor constructor, optional ElementDefinitionOptions options = {});
(CustomElementConstructor or undefined) get(DOMString name);
Promise<CustomElementConstructor> whenDefined(DOMString name);
[CEReactions] undefined upgrade(Node root);
};
callback CustomElementConstructor = HTMLElement ();
dictionary ElementDefinitionOptions {
DOMString extends;
};
Every
CustomElementRegistry
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
.
Every
CustomElementRegistry
also
has
an
element
definition
is
running
flag
which
is
used
to
prevent
reentrant
invocations
of
element
definition
.
It
is
initially
unset.
Every
CustomElementRegistry
also
has
a
when-defined
promise
map
,
mapping
valid
custom
element
names
to
promises.
It
is
used
to
implement
the
whenDefined()
method.
customElements
.
define
(
name
,
constructor
)
customElements
.
define
(
name
,
constructor
,
{
extends:
baseLocalName
})
NotSupportedError
"
DOMException
will
be
thrown
upon
trying
to
extend
a
custom
element
or
an
unknown
element.
customElements
.
get
(
name
)
customElements
.
whenDefined
(
name
)
SyntaxError
"
DOMException
if
not
given
a
valid
custom
element
name
.
customElements
.
upgrade
(
root
)
Support in all current engines.
Element
definition
is
a
process
of
adding
a
custom
element
definition
to
the
CustomElementRegistry
.
This
is
accomplished
by
the
define()
method.
When
invoked,
the
define(
name
,
constructor
,
options
)
method
must
run
these
steps:
If
IsConstructor
(
constructor
)
is
false,
then
throw
a
TypeError
.
If
name
is
not
a
valid
custom
element
name
,
then
throw
a
"
SyntaxError
"
DOMException
.
If
this
CustomElementRegistry
contains
an
entry
with
name
name
,
then
throw
a
"
NotSupportedError
"
DOMException
.
If
this
CustomElementRegistry
contains
an
entry
with
constructor
constructor
,
then
throw
a
"
NotSupportedError
"
DOMException
.
Let localName be name .
Let
extends
be
the
value
of
the
extends
member
of
options
,
or
null
if
no
such
member
exists.
If extends is not null, then:
If
extends
is
a
valid
custom
element
name
,
then
throw
a
"
NotSupportedError
"
DOMException
.
If
the
element
interface
for
extends
and
the
HTML
namespace
is
HTMLUnknownElement
(e.g.,
if
extends
does
not
indicate
an
element
definition
in
this
specification),
then
throw
a
"
NotSupportedError
"
DOMException
.
Set localName to extends .
If
this
CustomElementRegistry
's
element
definition
is
running
flag
is
set,
then
throw
a
"
NotSupportedError
"
DOMException
.
Set
this
CustomElementRegistry
's
element
definition
is
running
flag.
Let formAssociated be false.
Let disableInternals be false.
Let disableShadow be false.
Let
observedAttributes
be
an
empty
sequence<DOMString>
.
Run the following substeps while catching any exceptions:
Let prototype be Get ( constructor , "prototype"). Rethrow any exceptions.
If
Type
(
prototype
)
is
not
Object,
then
throw
a
TypeError
exception.
Let
lifecycleCallbacks
be
a
map
with
the
keys
"
connectedCallback
",
"
disconnectedCallback
",
"
adoptedCallback
",
and
"
attributeChangedCallback
",
each
of
which
belongs
to
an
entry
whose
value
is
null.
For each of the keys callbackName in lifecycleCallbacks , in the order listed in the previous step:
Let callbackValue be Get ( prototype , callbackName ). Rethrow any exceptions.
If
callbackValue
is
not
undefined,
then
set
the
value
of
the
entry
in
lifecycleCallbacks
with
key
callbackName
to
the
result
of
converting
callbackValue
to
the
Web
IDL
Function
callback
type.
Rethrow
any
exceptions
from
the
conversion.
If
the
value
of
the
entry
in
lifecycleCallbacks
with
key
"
attributeChangedCallback
"
is
not
null,
then:
Let observedAttributesIterable be Get ( constructor , "observedAttributes"). Rethrow any exceptions.
If
observedAttributesIterable
is
not
undefined,
then
set
observedAttributes
to
the
result
of
converting
observedAttributesIterable
to
a
sequence<DOMString>
.
Rethrow
any
exceptions
from
the
conversion.
Let
disabledFeatures
be
an
empty
sequence<DOMString>
.
Let disabledFeaturesIterable be Get ( constructor , "disabledFeatures"). Rethrow any exceptions.
If
disabledFeaturesIterable
is
not
undefined,
then
set
disabledFeatures
to
the
result
of
converting
disabledFeaturesIterable
to
a
sequence<DOMString>
.
Rethrow
any
exceptions
from
the
conversion.
Set
disableInternals
to
true
if
disabledFeatures
contains
"
internals
".
Set
disableShadow
to
true
if
disabledFeatures
contains
"
shadow
".
Let formAssociatedValue be Get ( constructor , "formAssociated"). Rethrow any exceptions.
Set
formAssociated
to
the
result
of
converting
formAssociatedValue
to
a
boolean
.
Rethrow
any
exceptions
from
the
conversion.
If
formAssociated
is
true,
for
each
of
"
formAssociatedCallback
",
"
formResetCallback
",
"
formDisabledCallback
",
and
"
formStateRestoreCallback
"
callbackName
:
Let callbackValue be Get ( prototype , callbackName ). Rethrow any exceptions.
If
callbackValue
is
not
undefined,
then
set
the
value
of
the
entry
in
lifecycleCallbacks
with
key
callbackName
to
the
result
of
converting
callbackValue
to
the
Web
IDL
Function
callback
type.
Rethrow
any
exceptions
from
the
conversion.
Then, perform the following substep, regardless of whether the above steps threw an exception or not:
Unset
this
CustomElementRegistry
's
element
definition
is
running
flag.
Finally, if the first set of substeps threw an exception, then rethrow that exception (thus terminating this algorithm). Otherwise, continue onward.
Let definition be a new custom element definition with name name , local name localName , constructor constructor , observed attributes observedAttributes , lifecycle callbacks lifecycleCallbacks , form-associated formAssociated , disable internals disableInternals , and disable shadow disableShadow .
Add
definition
to
this
CustomElementRegistry
.
Let
document
be
this
CustomElementRegistry
's
relevant
global
object
's
associated
Document
.
Let
upgrade
candidates
be
all
elements
that
are
shadow-including
descendants
of
document
,
whose
namespace
is
the
HTML
namespace
and
whose
local
name
is
localName
,
in
shadow-including
tree
order
.
Additionally,
if
extends
is
non-null,
only
include
elements
whose
is
value
is
equal
to
name
.
For each element element in upgrade candidates , enqueue a custom element upgrade reaction given element and definition .
If
this
CustomElementRegistry
's
when-defined
promise
map
contains
an
entry
with
key
name
:
Let promise be the value of that entry.
Resolve promise with constructor .
Delete
the
entry
with
key
name
from
this
CustomElementRegistry
's
when-defined
promise
map
.
Support in all current engines.
When
invoked,
the
get(
name
)
method
must
run
these
steps:
If
this
CustomElementRegistry
contains
an
entry
with
name
name
,
then
return
that
entry's
constructor
.
Otherwise, return undefined.
CustomElementRegistry/whenDefined
Support in all current engines.
When
invoked,
the
whenDefined(
name
)
method
must
run
these
steps:
If
name
is
not
a
valid
custom
element
name
,
then
return
a
new
promise
rejected
with
a
"
SyntaxError
"
DOMException
.
If
this
CustomElementRegistry
contains
an
entry
with
name
name
,
then
return
a
new
promise
resolved
with
that
entry's
constructor
.
Let
map
be
this
CustomElementRegistry
's
when-defined
promise
map
.
If map does not contain an entry with key name , create an entry in map with key name and whose value is a new promise.
Let promise be the value of the entry in map with key name .
Return promise .
The
whenDefined()
method
can
be
used
to
avoid
performing
an
action
until
all
appropriate
custom
elements
are
defined
.
In
this
example,
we
combine
it
with
the
:defined
pseudo-class
to
hide
a
dynamically-loaded
article's
contents
until
we're
sure
that
all
of
the
autonomous
custom
elements
it
uses
are
defined.
articleContainer.hidden = true;
fetch(articleURL)
.then(response => response.text())
.then(text => {
articleContainer.innerHTML = text;
return Promise.all(
[...articleContainer.querySelectorAll(":not(:defined)")]
.map(el => customElements.whenDefined(el.localName))
);
})
.then(() => {
articleContainer.hidden = false;
});
Support in all current engines.
When
invoked,
the
upgrade(
root
)
method
must
run
these
steps:
Let candidates be a list of all of root 's shadow-including inclusive descendant elements, in shadow-including tree order .
For each candidate of candidates , try to upgrade candidate .
The
upgrade()
method
allows
upgrading
of
elements
at
will.
Normally
elements
are
automatically
upgraded
when
they
become
connected
,
but
this
method
can
be
used
if
you
need
to
upgrade
before
you're
ready
to
connect
the
element.
const el = document.createElement("spider-man");
class SpiderMan extends HTMLElement {}
customElements.define("spider-man", SpiderMan);
console.assert(!(el instanceof SpiderMan)); // not yet upgraded
customElements.upgrade(el);
console.assert(el
instanceof
SpiderMan);
//
upgraded!
To upgrade an element , given as input a custom element definition definition and an element element , run the following steps:
If
element
's
custom
element
state
is
not
"
undefined
"
or
"
uncustomized
",
then
return.
One scenario where this can occur due to reentrant invocation of this algorithm, as in the following example:
<!DOCTYPE html>
<x-foo id="a"></x-foo>
<x-foo id="b"></x-foo>
<script>
// Defining enqueues upgrade reactions for both "a" and "b"
customElements.define("x-foo", class extends HTMLElement {
constructor() {
super();
const b = document.querySelector("#b");
b.remove();
// While this constructor is running for "a", "b" is still
// undefined, and so inserting it into the document will enqueue a
// second upgrade reaction for "b" in addition to the one enqueued
// by defining x-foo.
document.body.appendChild(b);
}
})
</script>
This
step
will
thus
bail
out
the
algorithm
early
when
upgrade
an
element
is
invoked
with
"
b
"
a
second
time.
Set element 's custom element definition to definition .
Set
element
's
custom
element
state
to
"
failed
".
It
will
be
set
to
"
custom
"
after
the
upgrade
succeeds
.
For
now,
we
set
it
to
"
failed
"
so
that
any
reentrant
invocations
will
hit
the
above
early-exit
step
.
For
each
attribute
in
element
's
attribute
list
,
in
order,
enqueue
a
custom
element
callback
reaction
with
element
,
callback
name
"
attributeChangedCallback
",
and
an
argument
list
containing
attribute
's
local
name,
null,
attribute
's
value,
and
attribute
's
namespace.
If
element
is
connected
,
then
enqueue
a
custom
element
callback
reaction
with
element
,
callback
name
"
connectedCallback
",
and
an
empty
argument
list.
Add element to the end of definition 's construction stack .
Let C be definition 's constructor .
Run the following substeps while catching any exceptions:
If
definition
's
disable
shadow
is
true
and
element
's
shadow
root
is
non-null,
then
throw
a
"
NotSupportedError
"
DOMException
.
This
is
needed
as
attachShadow()
does
not
use
look
up
a
custom
element
definition
while
attachInternals()
does.
Set
element
's
custom
element
state
to
"
precustomized
".
Let constructResult be the result of constructing C , with no arguments.
If
C
non-conformantly
uses
an
API
decorated
with
the
[CEReactions]
extended
attribute,
then
the
reactions
enqueued
at
the
beginning
of
this
algorithm
will
execute
during
this
step,
before
C
finishes
and
control
returns
to
this
algorithm.
Otherwise,
they
will
execute
after
C
and
the
rest
of
the
upgrade
process
finishes.
If
SameValue
(
constructResult
,
element
)
is
false,
then
throw
a
TypeError
.
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
HTMLElement
object
from
the
constructor.
Then, perform the following substep, regardless of whether the above steps threw an exception or not:
Remove the last entry from the end of definition 's construction stack .
Assuming
C
calls
super()
(as
it
will
if
it
is
conformant
),
and
that
the
call
succeeds,
this
will
be
the
already
constructed
marker
that
replaced
the
element
we
pushed
at
the
beginning
of
this
algorithm.
(The
HTML
element
constructor
carries
out
this
replacement.)
If
C
does
not
call
super()
(i.e.
it
is
not
conformant
),
or
if
any
step
in
the
HTML
element
constructor
throws,
then
this
entry
will
still
be
element
.
Finally, if the above steps threw an exception, then:
Set element 's custom element definition to null.
Empty element 's custom element reaction queue .
Rethrow the exception (thus terminating this algorithm).
If
the
above
steps
threw
an
exception,
then
element
's
custom
element
state
will
remain
"
failed
"
or
"
precustomized
".
If element is a form-associated custom element , then:
Reset
the
form
owner
of
element
.
If
element
is
associated
with
a
form
element,
then
enqueue
a
custom
element
callback
reaction
with
element
,
callback
name
"
formAssociatedCallback
",
and
«
the
associated
form
».
If
element
is
disabled
,
then
enqueue
a
custom
element
callback
reaction
with
element
,
callback
name
"
formDisabledCallback
"
and
«
true
».
Set
element
's
custom
element
state
to
"
custom
".
To try to upgrade an element , given as input an element element , run the following steps:
Let
definition
be
the
result
of
looking
up
a
custom
element
definition
given
element
's
node
document
,
element
's
namespace,
element
's
local
name,
and
element
's
is
value
.
If definition is not null, then enqueue a custom element upgrade reaction given element and definition .
A custom element possesses the ability to respond to certain occurrences by running author code:
When upgraded , its constructor is run, with no arguments.
When
it
becomes
connected
,
its
connectedCallback
is
called,
with
no
arguments.
When
it
becomes
disconnected
,
its
disconnectedCallback
is
called,
with
no
arguments.
When
it
is
adopted
into
a
new
document,
its
adoptedCallback
is
called,
given
the
old
document
and
new
document
as
arguments.
When
any
of
its
attributes
are
changed
,
appended
,
removed
,
or
replaced
,
its
attributeChangedCallback
is
called,
given
the
attribute's
local
name,
old
value,
new
value,
and
namespace
as
arguments.
(An
attribute's
old
or
new
value
is
considered
to
be
null
when
the
attribute
is
added
or
removed,
respectively.)
When
the
user
agent
resets
the
form
owner
of
a
form-associated
custom
element
and
doing
so
changes
the
form
owner,
its
formAssociatedCallback
is
called,
given
the
new
form
owner
(or
null
if
no
owner)
as
an
argument.
When
the
form
owner
of
a
form-associated
custom
element
is
reset
,
its
formResetCallback
is
called.
When
the
disabled
state
of
a
form-associated
custom
element
is
changed,
its
formDisabledCallback
is
called,
given
the
new
state
as
an
argument.
When
user
agent
updates
a
form-associated
custom
element
's
value
on
behalf
of
a
user,
its
formStateRestoreCallback
is
called,
given
the
new
value
and
a
string
indicating
a
reason,
"
restore
"
or
"
autocomplete
",
as
arguments.
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 similar-origin window agent has a custom element reactions stack , which is initially empty. A similar-origin window agent 's current element queue is the element queue at the top of its custom element reactions stack . Each item in the stack is an element queue , which is initially empty as well. 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.)
Each
custom
element
reactions
stack
has
an
associated
backup
element
queue
,
which
an
initially-empty
element
queue
.
Elements
are
pushed
onto
the
backup
element
queue
during
operations
that
affect
the
DOM
without
going
through
an
API
decorated
with
[CEReactions]
,
or
through
the
parser's
create
an
element
for
the
token
algorithm.
An
example
of
this
is
a
user-initiated
editing
operation
which
modifies
the
descendants
or
attributes
of
an
editable
element.
To
prevent
reentrancy
when
processing
the
backup
element
queue
,
each
custom
element
reactions
stack
also
has
a
processing
the
backup
element
queue
flag,
initially
unset.
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:
An upgrade reaction , which will upgrade the custom element and contains a custom element definition ; or
A callback reaction , which will call a lifecycle callback, and contains a callback function as well as a list of arguments.
This is all summarized in the following schematic diagram:
To enqueue an element on the appropriate element queue , given an element element , run the following steps:
Let reactionsStack be element 's relevant agent 's custom element reactions stack .
If reactionsStack is empty, then:
Add element to reactionsStack 's backup element queue .
If reactionsStack 's processing the backup element queue flag is set, then return.
Set reactionsStack 's processing the backup element queue flag.
Queue a microtask to perform the following steps:
Invoke custom element reactions in reactionsStack 's backup element queue .
Unset reactionsStack 's processing the backup element queue flag.
Otherwise, add element to element 's relevant agent 's current element queue .
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:
Let definition be element 's custom element definition .
Let callback be the value of the entry in definition 's lifecycle callbacks with key callbackName .
If callback is null, then return
If
callbackName
is
"
attributeChangedCallback
",
then:
Let attributeName be the first element of args .
If definition 's observed attributes does not contain attributeName , then return.
Add a new callback reaction to element 's custom element reaction queue , with callback function callback and arguments args .
Enqueue an element on the appropriate element queue given element .
To enqueue a custom element upgrade reaction , given an element element and custom element definition definition , run the following steps:
Add a new upgrade reaction to element 's custom element reaction queue , with custom element definition definition .
Enqueue an element on the appropriate element queue given element .
To invoke custom element reactions in an element queue queue , run the following steps:
While queue is not empty :
Let element be the result of dequeuing from queue .
Let reactions be element 's custom element reaction 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 an exception, catch it, and report the exception .
To
ensure
custom
element
reactions
are
triggered
appropriately,
we
introduce
the
[CEReactions]
IDL
extended
attribute
.
It
indicates
that
the
relevant
algorithm
is
to
be
supplemented
with
additional
steps
in
order
to
appropriately
track
and
invoke
custom
element
reactions
.
The
[CEReactions]
extended
attribute
must
take
no
arguments,
and
must
not
appear
on
anything
other
than
an
operation,
attribute,
setter,
or
deleter.
Additionally,
it
must
not
appear
on
readonly
attributes.
Operations,
attributes,
setters,
or
deleters
annotated
with
the
[CEReactions]
extended
attribute
must
run
the
following
steps
in
place
of
the
ones
specified
in
their
description:
Push a new element queue onto this object's relevant agent 's custom element reactions stack .
Run the originally-specified steps for this construct, catching any exceptions. If the steps return a value, let value be the returned value. If they throw an exception, let exception be the thrown exception.
Let queue be the result of popping from this object's relevant agent 's custom element reactions stack .
Invoke custom element reactions in queue .
If an exception exception was thrown by the original steps, rethrow exception .
If a value value was returned from the original steps, return value .
The intent behind this extended attribute is somewhat subtle. One way of accomplishing its goals would be to say that every operation, attribute, setter, and deleter on the platform must have these steps inserted, and to allow implementers to optimize away unnecessary cases (where no DOM mutation is possible that could cause custom element reactions to occur).
However, in practice this imprecision could lead to non-interoperable implementations of custom element reactions , as some implementations might forget to invoke these steps in some cases. Instead, we settled on the approach of explicitly annotating all relevant IDL constructs, as a way of ensuring interoperable behavior and helping implementations easily pinpoint all cases where these steps are necessary.
Any
nonstandard
APIs
introduced
by
the
user
agent
that
could
modify
the
DOM
in
such
a
way
as
to
cause
enqueuing
a
custom
element
callback
reaction
or
enqueuing
a
custom
element
upgrade
reaction
,
for
example
by
modifying
any
attributes
or
child
elements,
must
also
be
decorated
with
the
[CEReactions]
attribute.
As of the time of this writing, the following nonstandard or not-yet-standardized APIs are known to fall into this category:
HTMLElement
's
outerText
IDL
attribute
HTMLInputElement
's
webkitdirectory
and
incremental
IDL
attributes
HTMLLinkElement
's
scope
IDL
attribute
ShadowRoot
's
innerHTML
IDL
attribute
Certain
capabilities
are
meant
to
be
available
to
a
custom
element
author,
but
not
to
a
custom
element
consumer.
These
are
provided
by
the
element.attachInternals()
method,
which
returns
an
instance
of
ElementInternals
.
The
properties
and
methods
of
ElementInternals
allow
control
over
internal
features
which
the
user
agent
provides
to
all
elements.
attachInternals()
Returns
an
ElementInternals
object
targeting
the
custom
element
element
.
Throws
an
exception
if
element
is
not
a
custom
element
,
if
the
"
internals
"
feature
was
disabled
as
part
of
the
element
definition,
or
if
it
is
called
twice
on
the
same
element.
Each
HTMLElement
has
an
attached
internals
boolean,
initially
false.
The
attachInternals()
method
steps
are:
If
this
's
is
value
is
not
null,
then
throw
a
"
NotSupportedError
"
DOMException
.
Let
definition
be
the
result
of
looking
up
a
custom
element
definition
given
this's
node
document
,
its
namespace,
its
local
name,
and
null
as
the
is
value
.
If
definition
is
null,
then
throw
an
"
NotSupportedError
"
DOMException
.
If
definition
's
disable
internals
is
true,
then
throw
a
"
NotSupportedError
"
DOMException
.
If
this
's
attached
internals
is
true,
then
throw
an
"
NotSupportedError
"
DOMException
.
If
this
's
custom
element
state
is
not
"
precustomized
"
or
"
custom
",
then
throw
a
"
NotSupportedError
"
DOMException
.
Set this 's attached internals to true.
Return
a
new
ElementInternals
instance
whose
target
element
is
this
.
ElementInternals
interface
The
IDL
for
the
ElementInternals
interface
is
as
follows,
with
the
various
operations
and
attributes
defined
in
the
following
sections:
[Exposed=Window]
interface ElementInternals {
// Shadow root access
readonly attribute ShadowRoot
? shadowRoot;
// Form-associated custom elements
undefined setFormValue((File or USVString or FormData)? value,
optional (File or USVString or FormData)? state);
readonly attribute HTMLFormElement? form;
undefined setValidity(optional ValidityStateFlags flags = {},
optional DOMString message,
optional HTMLElement anchor);
readonly attribute boolean willValidate;
readonly attribute ValidityState validity;
readonly attribute DOMString validationMessage;
boolean checkValidity();
boolean reportValidity();
readonly attribute NodeList labels;
};
// Accessibility semantics
ElementInternals includes ARIAMixin;
dictionary ValidityStateFlags {
boolean valueMissing = false;
boolean typeMismatch = false;
boolean patternMismatch = false;
boolean tooLong = false;
boolean tooShort = false;
boolean rangeUnderflow = false;
boolean rangeOverflow = false;
boolean stepMismatch = false;
boolean badInput = false;
boolean customError = false;
};
Each
ElementInternals
has
a
target
element
,
which
is
a
custom
element
.
shadowRoot
Returns
the
ShadowRoot
for
internals
's
target
element
,
if
the
target
element
is
a
shadow
host
,
or
null
otherwise.
The
shadowRoot
getter
steps
are:
Let target be this 's target element .
If target is not a shadow host , then return null.
Let shadow be target 's shadow root .
If shadow 's available to element internals is false, then return null.
Return shadow .
setFormValue
(
value
)
Sets both the state and submission value of internals 's target element to value .
If value is null, the element won't participate in form submission.
setFormValue
(
value
,
state
)
Sets the submission value of internals 's target element to value , and its state to state .
If value is null, the element won't participate in form submission.
form
Returns the form owner of internals 's target element .
setValidity
(
flags
,
message
[,
anchor
])
Marks
internals
's
target
element
as
suffering
from
the
constraints
indicated
by
the
flags
argument,
and
sets
the
element's
validation
message
to
message
.
If
anchor
is
specified,
the
user
agent
might
use
it
to
indicate
problems
with
the
constraints
of
internals
's
target
element
when
the
form
owner
is
validated
interactively
or
reportValidity()
is
called.
setValidity
({})
Marks internals 's target element as satisfying its constraints .
willValidate
Returns true if internals 's target element will be validated when the form is submitted; false otherwise.
validity
Returns
the
ValidityState
object
for
internals
's
target
element
.
validationMessage
Returns the error message that would be shown to the user if internals 's target element was to be checked for validity.
checkValidity()
Returns
true
if
internals
's
target
element
has
no
validity
problems;
false
otherwise.
Fires
an
invalid
event
at
the
element
in
the
latter
case.
reportValidity()
Returns
true
if
internals
's
target
element
has
no
validity
problems;
otherwise,
returns
false,
fires
an
invalid
event
at
the
element,
and
(if
the
event
isn't
canceled)
reports
the
problem
to
the
user.
labels
Returns
a
NodeList
of
all
the
label
elements
that
internals
's
target
element
is
associated
with.
Each
form-associated
custom
element
has
submission
value
.
It
is
used
to
provide
one
or
more
entries
on
form
submission.
The
initial
value
of
submission
value
is
null,
and
submission
value
can
be
null,
a
string,
a
File
,
or
a
list
of
entries
.
Each
form-associated
custom
element
has
state
.
It
is
information
with
which
the
user
agent
can
restore
a
user's
input
for
the
element.
The
initial
value
of
state
is
null,
and
state
can
be
null,
a
string,
a
File
,
or
a
list
of
entries
.
The
setFormValue()
method
is
used
by
the
custom
element
author
to
set
the
element's
submission
value
and
state
,
thus
communicating
these
to
the
user
agent.
When
the
user
agent
believes
it
is
a
good
idea
to
restore
a
form-associated
custom
element
's
state
,
for
example
after
navigation
or
restarting
the
user
agent,
they
may
enqueue
a
custom
element
callback
reaction
with
that
element,
callback
name
"
formStateRestoreCallback
",
and
an
argument
list
containing
the
state
to
be
restored,
and
"restore"
.
If
the
user
agent
has
a
form-filling
assist
feature,
then
when
the
feature
is
invoked,
it
may
enqueue
a
custom
element
callback
reaction
with
a
form-associated
custom
element
,
callback
name
"
formStateRestoreCallback
",
and
an
argument
list
containing
the
state
value
determined
by
history
of
state
value
and
some
heuristics,
and
"autocomplete"
.
In general, the state is information specified by a user, and the submission value is a value after canonicalization or sanitization, suitable for submission to the server. The following examples makes this concrete:
Suppose
that
we
have
a
form-associated
custom
element
which
asks
a
user
to
specify
a
date.
The
user
specifies
"3/15/2019"
,
but
the
control
wishes
to
submit
"2019-03-15"
to
the
server.
"3/15/2019"
would
be
a
state
of
the
element,
and
"2019-03-15"
would
be
a
submission
value
.
Suppose
you
develop
a
custom
element
emulating
a
the
behavior
of
the
existing
checkbox
input
type.
Its
submission
value
would
be
the
value
of
its
value
content
attribute,
or
the
string
"on"
.
Its
state
would
be
one
of
"checked"
,
"unchecked"
,
"checked/indeterminate"
,
or
"unchecked/indeterminate"
.
The
setFormValue(
value
,
state
)
method
steps
are:
Let element be this 's target element .
If
element
is
not
a
form-associated
custom
element
,
then
throw
a
"
NotSupportedError
"
DOMException
.
Set
target
element
's
submission
value
to
value
if
value
is
not
a
FormData
object,
or
to
a
clone
of
the
entry
list
associated
with
value
otherwise.
If the state argument of the function is omitted, set element 's state to its submission value .
Otherwise,
if
state
is
a
FormData
object,
set
element
's
state
to
clone
of
the
entry
list
associated
with
state
.
Otherwise, set element 's state to state .
Each
form-associated
custom
element
has
validity
flags
named
valueMissing
,
typeMismatch
,
patternMismatch
,
tooLong
,
tooShort
,
rangeUnderflow
,
rangeOverflow
,
stepMismatch
,
and
customError
.
They
are
false
initially.
Each form-associated custom element has a validation message string. It is the empty string initially.
Each form-associated custom element has a validation anchor element. It is null initially.
The
setValidity(
flags
,
message
,
anchor
)
method
steps
are:
Let element be this 's target element .
If
element
is
not
a
form-associated
custom
element
,
then
throw
a
"
NotSupportedError
"
DOMException
.
If
flags
contains
one
or
more
true
values
and
message
is
not
given
or
is
the
empty
string,
then
throw
a
TypeError
.
For each entry flag → value of flags , set element 's validity flag with the name flag to value .
Set element 's validation message to the empty string if message is not given or all of element 's validity flags are false, or to message otherwise.
If
element
's
customError
validity
flag
is
true,
then
set
element
's
custom
validity
error
message
to
element
's
validation
message
.
Otherwise,
set
element
's
custom
validity
error
message
to
the
empty
string.
Set
element
's
validation
anchor
to
null
if
anchor
is
not
given.
Otherwise,
if
anchor
is
not
a
shadow-including
descendant
of
element
,
then
throw
a
"
NotFoundError
"
DOMException
.
Otherwise,
set
element
's
validation
anchor
to
anchor
.
The
validationMessage
getter
steps
are
to
return
the
validation
message
of
this
's
target
element
.
The entry construction algorithm for a form-associated custom element , given an element element and a list entry list , consists of the following steps:
If element 's submission value is a list of entries , then append each item of element 's submission value to entry list , and return.
In
this
case,
user
agent
does
not
refer
to
the
name
content
attribute
value.
An
implementation
of
form-associated
custom
element
is
responsible
to
decide
names
of
entries
.
They
can
be
the
name
content
attribute
value,
they
can
be
strings
based
on
the
name
content
attribute
value,
or
they
can
be
unrelated
to
the
name
content
attribute.
If
the
element
does
not
have
a
name
attribute
specified,
or
its
name
attribute's
value
is
the
empty
string,
then
return.
If
the
element's
submission
value
is
not
null,
append
an
entry
to
entry
list
with
the
name
attribute
value
and
the
submission
value
.
role
[
=
value
]
Sets
or
retrieves
the
default
ARIA
role
for
internals
's
target
element
,
which
will
be
used
unless
the
page
author
overrides
it
using
the
role
attribute.
aria*
[
=
value
]
Sets
or
retrieves
various
default
ARIA
states
or
property
values
for
internals
's
target
element
,
which
will
be
used
unless
the
page
author
overrides
them
using
the
aria-*
attributes.
Each custom element has a native accessibility semantics map , which is a map , initially empty. See the Requirements related to ARIA and to platform accessibility APIs section for information on how this impacts platform accessibility APIs.
ElementInternals
includes
the
ARIAMixin
mixin.
The
accessors
provided
by
this
mixin
are
used
to
manipulate
the
target
element
's
native
accessibility
semantics
map
,
as
follows:
The
ARIAMixin
getter
steps
for
ElementInternals
,
given
internals
,
idlAttribute
,
and
contentAttribute
,
are:
Let map be internals 's target element 's native accessibility semantics map .
If map [ contentAttribute ] exists , then return it.
Return null.
The
ARIAMixin
setter
steps
for
ElementInternals
,
given
internals
,
idlAttribute
,
contentAttribute
,
and
value
,
are:
Let map be internals 's target element 's native accessibility semantics map .
If value is null, then remove map [ contentAttribute ].
Otherwise, set map [ contentAttribute ] to value .