The Hidden Power of Custom States For Web Components

Danny Moerkerke on 2022-10-11

A crucial step in the evolution of Custom Elements

Photo by Justus Menke on Unsplash

In my previous articles “Web Components Can Now Be Native Form Elements” and “Native Form Validation Of Web Components”, I wrote about the ElementInternals property that enables Custom Elements to be associated with a form.

This interface also enables developers to associate custom states with Custom Elements and style them based on these states.

The states property of ElementInternals returns a CustomStateSet that stores a list of possible states for a Custom Element to be in, and allows states to be added and removed from the set.

Each state in the set is represented by a string that has the same form as a CSS Custom Property, namely--mystate.

These states can then be accessed from CSS with the custom state pseudo-class in the same way that built-in states can be accessed.

For example, a checkbox that is checked can be accessed from CSS using the built-in :checked pseudo-class:

input[type=”checkbox”]:checked {
 outline: solid green;

Another example is a disabled button that can be accessed from CSS using the :disabled pseudo-class:

button:disabled {
 cursor: not-allowed;

In the same way, an element containing the custom state --mystate can be accessed from CSS like this:

my-element:--mystate {
 color: red;

A use case for Custom States

Custom states unlock a powerful feature.

They enable Web Components to be styled based on internal states without having to add attributes or classes to the component to reflect these states, so they stay fully internal.

For example, let’s say you have a <video-player> component that shows a play button to play a video.

When the play button is clicked and the video starts playing, you want this play button to be hidden and a pause button to be shown.

Then, when the pause button is clicked, it will be hidden and the play button will be shown again.