Start · Sprachen · JavaScript · Referenz · CustomStateSet

CustomStateSet

Schnittstelle

Set-ähnliche Menge benutzerdefinierter Zustände eines autonomen Custom Elements, die per CSS-Pseudoklasse <code>:state()</code> abgefragt werden können.

seit JavaScript Baseline 2024: Chrome 125, Edge 125, Firefox 126, Kategorie: webapi

Signatur

interface CustomStateSet

Beschreibung

Das Interface CustomStateSet speichert die benutzerdefinierten Zustände eines autonomen Custom Elements. Man erhält eine Instanz nicht über einen Konstruktor, sondern über die Eigenschaft ElementInternals.states. Dieses Objekt liefert this.attachInternals() innerhalb der Elementklasse.

Jeder Zustand ist eine Zeichenkette. Über die CSS-Pseudoklasse :state(name) lässt sich das Element dann gezielt gestalten, zum Beispiel mit my-toggle:state(checked). Das ist genau der Weg, auf dem eingebaute Elemente Zustände wie :checked oder :invalid anbieten. Die Zustände liegen intern: Anders als Attribute oder Klassen kann Code außerhalb des Elements sie nicht einfach ändern.

CustomStateSet verhält sich wie ein Set. Es gibt die Methoden add(), delete(), has(), clear(), forEach(), entries(), keys() und values(), die Eigenschaft size und einen Iterator (for...of). Die Reihenfolge der Einfügung bleibt erhalten.

Typische Einsatzfälle sind Umschalter wie checked oder open, Ladezustände wie loading oder error und Validierungszustände in formularbezogenen Custom Elements.

Parameter

Name Typ Default Beschreibung
$value Pflicht string Name des Zustands bei add(value), delete(value) und has(value). In aktuellen Browsern ist jede Zeichenkette erlaubt, z. B. "checked". Die alte Schreibweise mit Präfix ("--checked") gilt als veraltet.

Rückgabewert

Typ
CustomStateSet
Beschreibung
Die Eigenschaft ElementInternals.states gibt das CustomStateSet des Elements zurück. add() gibt die Menge selbst zurück, delete() und has() geben boolean zurück, clear() gibt undefined zurück.

Beispiele

Umschalter mit :state(checked)

class MyToggle extends HTMLElement {
  #internals;
  constructor() {
    super();
    this.#internals = this.attachInternals();
    this.addEventListener('click', () => (this.checked = !this.checked));
  }
  get checked() {
    return this.#internals.states.has('checked');
  }
  set checked(value) {
    if (value) this.#internals.states.add('checked');
    else this.#internals.states.delete('checked');
  }
}
customElements.define('my-toggle', MyToggle);

// CSS: my-toggle:state(checked) { background: green; }
const toggle = document.createElement('my-toggle');
document.body.append(toggle);
toggle.checked = true;
console.log(toggle.matches(':state(checked)'));
true

Ladezustände einer Komponente verwalten

class DataView extends HTMLElement {
  #internals = this.attachInternals();

  async connectedCallback() {
    const { states } = this.#internals;
    states.clear();
    states.add('loading');
    try {
      const res = await fetch(this.getAttribute('src'));
      if (!res.ok) throw new Error(res.statusText);
      this.textContent = await res.text();
      states.add('loaded');
    } catch {
      states.add('error');
    } finally {
      states.delete('loading');
    }
  }
}
customElements.define('data-view', DataView);
// CSS: data-view:state(error) { color: crimson; }

Zustände abfragen und durchlaufen

class StatusBox extends HTMLElement {
  internals = this.attachInternals();
}
customElements.define('status-box', StatusBox);

const box = new StatusBox();
const { states } = box.internals;
states.add('active').add('highlighted');

console.log(states.size);
console.log([...states]);
console.log(states.has('active'));
console.log(states.delete('missing'));
2 ["active", "highlighted"] true false

// Wichtig · Fallstricke

  • Nur für autonome Custom Elements: Bei eingebauten Elementen und bei angepassten eingebauten Elementen (is="…") wirft attachInternals() einen NotSupportedError. attachInternals() darf pro Element nur einmal aufgerufen werden.
  • Veraltete Syntax: Ältere Chrome-Versionen (90–124) kannten nur Zustände mit ---Präfix und die CSS-Syntax :--checked. Der aktuelle Standard ist :state(checked). Wenn du alte Browser unterstützen musst, versuche add('checked') in einem try/catch und weiche bei einem Fehler auf '--checked' aus.
  • Kapselung: Gib das ElementInternals-Objekt nicht öffentlich heraus, sondern halte es in einem privaten Feld (#internals). Sonst kann Code außerhalb des Elements die Zustände ändern.
  • Selektoren: :state() funktioniert auch in :host(:state(x)) innerhalb des Shadow DOM und mit ::part(). Ältere Browser erkennen die Pseudoklasse nicht und verwerfen dann die gesamte CSS-Regel. Deshalb solltest du solche Selektoren nicht mit anderen in derselben Regel kombinieren.
  • Zustände ersetzen keine ARIA-Attribute. Für die Barrierefreiheit setzt du zusätzlich z. B. internals.ariaChecked.