CSS Portal

:state() CSS Pseudo Class

If this site has been useful, we’d love your support! Consider buying us a coffee to keep things going strong!

Description

The :state() pseudo-class is an experimental CSS selector used to style custom elements based on their internal state, as defined through the ElementInternals state API. It allows authors to apply styles when a custom element enters a named state - similar in spirit to how built-in form controls respond to states like :hover or :checked, but fully customizable.

Unlike traditional pseudo-classes, :state() is not automatically managed by the browser. Instead, the state must be explicitly defined and toggled via JavaScript using the element’s internal state map.

What :state() Does

The :state() pseudo-class matches a custom element when it has a specific named state set internally. This makes it possible to create semantic, reusable UI components that expose meaningful visual states without relying on attributes or classes.

Example syntax:

my-toggle:state(active) {
  background-color: green;
}

In this example, the styles apply only when the custom element <my-toggle> is in the active state.

Defining a State (JavaScript)

States are defined using the ElementInternals.states API inside a custom element class:

class MyToggle extends HTMLElement {
  constructor() {
    super();
    this._internals = this.attachInternals();
  }

  activate() {
    this._internals.states.add("active");
  }

  deactivate() {
    this._internals.states.delete("active");
  }
}

customElements.define("my-toggle", MyToggle);

Once the "active" state is added, it can be targeted using :state() in CSS.

Example Usage

<my-toggle id="toggle"></my-toggle>
my-toggle:state(active) {
  border: 2px solid green;
  background: #e6ffe6;
}
document.getElementById("toggle").addEventListener("click", e => {
  e.target.activate();
});

When to Use :state()

Use :state() when:

  • You are building custom elements
  • You want encapsulated, semantic state styling
  • You want to avoid relying on class toggling or data attributes
  • You need better integration with the browser’s styling model

Important Notes

  • :state() only works with custom elements, not standard HTML elements like button.
  • Browser support is currently limited and experimental, so it should be used cautiously in production.
  • It is part of the evolving CSS Selectors Level 4 specification.

Syntax

:state(<custom identifier>) {
  /* ... */
}

Values

  • <custom identifier>The :state() pseudo-class takes as its argument a custom identifier that represents the state of the custom element to match.

Example

<my-toggle-button>Click Me</my-toggle-button>

<script>
class MyToggleButton extends HTMLElement {
constructor() {
super();
// 1. Create the internals object
this._internals = this.attachInternals();
this._checked = false;

this.addEventListener('click', () => {
this._checked = !this._checked;

// 2. Toggle the custom state
if (this._checked) {
this._internals.states.add('--checked');
} else {
this._internals.states.delete('--checked');
}
});
}
}

// Register the element
customElements.define('my-toggle-button', MyToggleButton);
</script>
/* Default style for the custom element */
my-toggle-button {
padding: 10px 20px;
border: 2px solid gray;
cursor: pointer;
display: inline-block;
transition: all 0.3s ease;
}

/* Styling based on the custom internal state */
my-toggle-button:state(--checked) {
background-color: #4CAF50;
color: white;
border-color: #2E7D32;
}

/* You can also use it with other pseudo-classes */
my-toggle-button:state(--checked):hover {
background-color: #45a049;
}

Browser Support

The following information will show you the current browser support for the CSS :state() pseudo class. Hover over a browser icon to see the version that first introduced support for this CSS psuedo class.

This psuedo class is supported by all modern browsers.
Desktop
Chrome
Edge
Firefox
Opera
Safari
Tablets & Mobile
Chrome Android
Firefox Android
Opera Android
Safari iOS
Samsung Internet
Android WebView
-

Last updated by CSSPortal on: 31st December 2025

If this site has been useful, we’d love your support! Consider buying us a coffee to keep things going strong!