Signatur
Beschreibung
Mit add() setzt ein autonomes Custom Element einen eigenen Zustand, zum Beispiel "checked", "loading" oder "invalid". Das CustomStateSet erreicht man über ElementInternals.states. Die Instanz dazu liefert this.attachInternals() im Konstruktor des Elements.
Ist ein Zustand gesetzt, passt die CSS-Pseudoklasse :state(name) auf das Element, von außen etwa mit my-toggle:state(checked) und im Shadow DOM mit :host(:state(checked)). Anders als Attribute oder Klassen sind diese Zustände intern: Nutzer des Elements können sie nicht von außen setzen oder überschreiben. Die Komponente kontrolliert ihren Zustand also selbst und gibt ihn trotzdem zum Gestalten frei, ähnlich wie bei eingebauten Pseudoklassen wie :checked.
CustomStateSet verhält sich wie ein Set. Ist der Wert schon enthalten, ändert add() nichts. Zum Entfernen dient delete(), zum Prüfen has(). Zwischen den Zuständen umschalten kann man also mit add()/delete().
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $value Pflicht | string | Name des benutzerdefinierten Zustands, z. B. "checked". Er wird in CSS als :state(checked) abgefragt. Andere Werte werden in einen String umgewandelt. |
Rückgabewert
CustomStateSet selbst zurück. MDN gibt teils undefined an, deshalb sollte man sich nicht auf Verkettung verlassen.Beispiele
Umschaltbares Element mit Zustand „checked“
class MyToggle extends HTMLElement {
#internals;
constructor() {
super();
this.#internals = this.attachInternals();
this.addEventListener('click', () => this.toggle());
}
get checked() {
return this.#internals.states.has('checked');
}
toggle() {
if (this.checked) {
this.#internals.states.delete('checked');
} else {
this.#internals.states.add('checked');
}
console.log('checked:', this.checked);
}
}
customElements.define('my-toggle', MyToggle);
const toggle = document.createElement('my-toggle');
toggle.textContent = 'Schalter';
document.body.append(toggle);
toggle.click();
Zustand per CSS gestalten
const style = document.createElement('style');
style.textContent = `
my-toggle { padding: 4px 8px; border: 1px solid #888; cursor: pointer; }
my-toggle:state(checked) { background: seagreen; color: white; }
`;
document.head.append(style);
// Nach toggle.click() aus Beispiel 1 ist das Element grün hinterlegt
console.log(document.querySelector('my-toggle')?.matches(':state(checked)'));
Ladezustand bei asynchroner Arbeit
class DataView extends HTMLElement {
#internals = this.attachInternals();
async load(url) {
this.#internals.states.add('loading');
try {
const res = await fetch(url);
this.textContent = (await res.json()).title;
this.#internals.states.delete('error');
} catch {
this.#internals.states.add('error');
} finally {
this.#internals.states.delete('loading');
}
}
}
customElements.define('data-view', DataView);
const view = document.createElement('data-view');
document.body.append(view);
view.load('https://jsonplaceholder.typicode.com/todos/1');
console.log(view.matches(':state(loading)'));
// Wichtig · Fallstricke
- Nur für autonome Custom Elements:
attachInternals()funktioniert nicht bei eingebauten Elementen und nicht bei angepassten eingebauten Elementen (extends: 'button'). In diesen Fällen wird einNotSupportedErrorgeworfen. - Alte Chromium-Syntax: Chrome/Edge 90–124 unterstützten nur Namen mit doppeltem Bindestrich (
add('--checked')) und das CSS:--checked. Namen ohne Bindestriche lösten dort einenSyntaxErroraus. Falls alte Versionen unterstützt werden müssen, den Aufruf intry { states.add('checked') } catch { states.add('--checked') }einpacken und beide Selektoren im CSS angeben. - Browserunterstützung: Seit 2024 in allen aktuellen Browsern verfügbar (Chrome 125, Firefox 126, Safari 17.4). Unterstützung prüfen mit
'CustomStateSet' in window. - Zustände ersetzen keine ARIA-Attribute. Für Barrierefreiheit zusätzlich z. B.
internals.ariaCheckedsetzen. - Ist der Wert schon enthalten, passiert nichts. Es gibt keinen Fehler und kein Duplikat.