One of the key features of web components is the ability to create custom elements: that is, HTML elements whose behavior is defined by the web developer, that extend the set of elements available in the browser.
In the class constructor, you can set up initial state and default values, register event listeners and perhaps create a shadow root. At this point, you should not inspect the element's attributes or children, or add new attributes or children. See Requirements for custom element constructors and reactions for the complete set of requirements.
Once your custom element is registered, the browser will call certain methods of your class when code in the page interacts with your custom element in certain ways. By providing an implementation of these methods, which the specification calls lifecycle callbacks, you can run code in response to these events.
Like built-in elements, custom elements can use HTML attributes to configure the element's behavior. To use attributes effectively, an element has to be able to respond to changes in an attribute's value. To do this, a custom element needs to add the following members to the class that implements the custom element:
Note that if the element's HTML declaration includes an observed attribute, then attributeChangedCallback() will be called after the attribute is initialized, when the element's declaration is parsed for the first time. So in the following example, attributeChangedCallback() will be called when the DOM is parsed, even if the attribute is never changed again:
Built in HTML elements can have different states, such as "hover", "disabled", and "read only". Some of these states can be set as attributes using HTML or JavaScript, while others are internal, and cannot. Whether external or internal, commonly these states have corresponding CSS pseudo-classes that can be used to select and style the element when it is in a particular state.
Autonomous custom elements (but not elements based on built-in elements) also allow you to define states and select against them using the :state() pseudo-class function. The code below shows how this works using the example of an autonomous custom element that has an internal state "collapsed".
The collapsed state is represented as a boolean property (with setter and getter methods) that is not visible outside of the element. To make this state selectable in CSS the custom element first calls HTMLElement.attachInternals() in its constructor in order to attach an ElementInternals object, which in turn provides access to a CustomStateSet through the ElementInternals.states property. The setter for the (internal) collapsed state adds the identifier hidden to the CustomStateSet when the state is true, and removes it when the state is false. The identifier is just a string: in this case we called it hidden, but we could have just as easily called it collapsed.
We can use the identifier added to the custom element's CustomStateSet (this._internals.states) for matching the element's custom state. This is matched by passing the identifier to the :state() pseudo-class. For example, below we select on the hidden state being true (and hence the element's collapsed state) using the :hidden selector, and remove the border.
The :state() pseudo-class can also be used within the :host() pseudo-class function to match a custom state within a custom element's shadow DOM. Additionally, the :state() pseudo-class can be used after the ::part() pseudo-element to match the shadow parts of a custom element that is in a particular state.
In the rest of this guide we'll look at a few example custom elements. You can find the source for all these examples, and more, in the web-components-examples repository, and you can see them all live at -components-examples/.
First, we'll look at an autonomous custom element. The custom element takes an image icon and a text string as attributes, and embeds the icon into the page. When the icon is focused, it displays the text in a pop up information box to provide further in-context information.
In the above example we apply styles to the shadow DOM using a element, but you can reference an external stylesheet from a element instead. In this example we'll modify the custom element to use an external stylesheet.
Many modern browsers implement an optimization for tags either cloned from a common node or that have identical text, to allow them to share a single backing stylesheet. With this optimization the performance of external and internal styles should be similar.
Note that in this case we must ensure that the script defining our custom element is executed after the DOM has been fully parsed, because connectedCallback() is called as soon as the expanding list is added to the DOM, and at that point its children have not been added yet, so the querySelectorAll() calls will not find any items. One way to ensure this is to add the defer attribute to the line that includes the script:
So far we've seen only one lifecycle callback in action: connectedCallback(). In the final example, , we'll see some of the others. The autonomous custom element draws a square whose size and color are determined by two attributes, named "size" and "color".
The attributeChangedCallback() callback is run whenever one of the element's attributes is changed in some way. As you can see from its parameters, it is possible to act on attributes individually, looking at their name, and old and new attribute values. In this case however, we are just running the updateStyle() function again to make sure that the square's style is updated as per the new values:
Note that to get the attributeChangedCallback() callback to fire when an attribute changes, you have to observe the attributes. This is done by specifying a static get observedAttributes() method inside the custom element class - this should return an array containing the names of the attributes you want to observe:
\n Built in HTML elements can have different states, such as \"hover\", \"disabled\", and \"read only\".\n Some of these states can be set as attributes using HTML or JavaScript, while others are internal, and cannot.\n Whether external or internal, commonly these states have corresponding CSS pseudo-classes that can be used to select and style the element when it is in a particular state.\n
\n Autonomous custom elements (but not elements based on built-in elements) also allow you to define states and select against them using the :state() pseudo-class function.\n The code below shows how this works using the example of an autonomous custom element that has an internal state \"collapsed\".\n
\n The collapsed state is represented as a boolean property (with setter and getter methods) that is not visible outside of the element.\n To make this state selectable in CSS the custom element first calls HTMLElement.attachInternals() in its constructor in order to attach an ElementInternals object, which in turn provides access to a CustomStateSet through the ElementInternals.states property.\n The setter for the (internal) collapsed state adds the identifier hidden to the CustomStateSet when the state is true, and removes it when the state is false.\n The identifier is just a string: in this case we called it hidden, but we could have just as easily called it collapsed.\n
\n We can use the identifier added to the custom element's CustomStateSet (this._internals.states) for matching the element's custom state.\n This is matched by passing the identifier to the :state() pseudo-class.\n For example, below we select on the hidden state being true (and hence the element's collapsed state) using the :hidden selector, and remove the border.\n
c80f0f1006