Signatur
Beschreibung
Die Methode has() des Interfaces CustomStateSet gibt einen booleschen Wert zurück. Er zeigt an, ob der übergebene String als Custom State im Set steht. Ein CustomStateSet bekommst du über ElementInternals.states. Das geht nur in einem autonomen benutzerdefinierten Element, das this.attachInternals() aufgerufen hat.
Mit Custom States machen Web Components eigene Zustände nach außen sichtbar, ähnlich wie eingebaute Pseudoklassen wie :checked oder :disabled. Jeden Wert im Set kannst du in CSS mit der Pseudoklasse :state(name) ansprechen. Mit has() fragst du diesen Zustand im JavaScript-Code der Komponente ab. Das brauchst du zum Beispiel, um einen Zustand umzuschalten, um Ereignisse davon abhängig auszulösen oder um Getter wie get checked() umzusetzen.
CustomStateSet verhält sich wie ein Set, das nur Strings enthält. has() vergleicht deshalb exakt und unterscheidet Groß- und Kleinschreibung. Der Aufruf ändert nichts am Element und löst keine Neuberechnung der Stile aus.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $value Pflicht | string | Name des gesuchten Custom States, z. B. "checked". Werte, die keine Strings sind, werden nach WebIDL-Regeln in einen String umgewandelt. |
Beispiele
Zustand in einer Checkbox-Komponente umschalten
class MyCheckbox extends HTMLElement {
#internals;
constructor() {
super();
this.#internals = this.attachInternals();
this.addEventListener('click', () => this.toggle());
}
get checked() {
return this.#internals.states.has('checked');
}
toggle() {
const { states } = this.#internals;
if (states.has('checked')) {
states.delete('checked');
} else {
states.add('checked');
}
console.log('checked:', this.checked);
}
}
customElements.define('my-checkbox', MyCheckbox);
const box = document.createElement('my-checkbox');
document.body.append(box);
box.click();
box.click();
Groß- und Kleinschreibung beachten
class StatusBadge extends HTMLElement {
constructor() {
super();
this.internals = this.attachInternals();
this.internals.states.add('loading');
}
}
customElements.define('status-badge', StatusBadge);
const badge = new StatusBadge();
const { states } = badge.internals;
console.log(states.has('loading'));
console.log(states.has('Loading'));
console.log(states.has('ready'));
Nur bei echter Zustandsänderung ein Event auslösen
class ToggleSwitch extends HTMLElement {
#internals = this.attachInternals();
setOn(on) {
const { states } = this.#internals;
if (states.has('on') === on) return; // keine Änderung
on ? states.add('on') : states.delete('on');
this.dispatchEvent(new CustomEvent('change', { detail: { on } }));
}
}
customElements.define('toggle-switch', ToggleSwitch);
const sw = document.createElement('toggle-switch');
sw.addEventListener('change', (e) => console.log('change:', e.detail.on));
sw.setOn(true);
sw.setOn(true); // löst nichts aus
sw.setOn(false);
/* CSS dazu:
toggle-switch:state(on) { background: green; }
*/
// Wichtig · Fallstricke
- Nur für autonome Custom Elements:
attachInternals()wirft bei eingebauten Elementen und bei angepassten eingebauten Elementen (is="…") einenNotSupportedError. Außerhalb der Komponente kommst du nur an das Set, wenn die KomponenteElementInternalsbewusst nach außen gibt. Üblicherweise hält man es in einem privaten Feld. - Alte Syntax: Chrome/Edge 90–124 kannten nur die Form mit Präfix
--nameund die CSS-Syntax:--name. Werte ohne--haben dort beiadd()einen Fehler ausgelöst.states.has('--checked')undstates.has('checked')sind verschiedene Werte. Wenn du ältere Browser unterstützen willst, musst du beide Varianten berücksichtigen. - Feature-Erkennung: Zum Beispiel mit
'states' in ElementInternals.prototypeoder in CSS mitCSS.supports('selector(:state(x))'). - Die Custom States sind nicht mit Attributen verknüpft. Sie erscheinen nicht im DOM und werden auch nicht serialisiert (
outerHTML). Wenn der Zustand von außen gesetzt werden soll, synchronisiere ihn selbst mit einem Attribut oder einer Eigenschaft. has()hat die Laufzeit einer normalen Set-Abfrage und kostet praktisch nichts. Es löst keine Neuberechnung der Stile aus.