Signatur
Beschreibung
Die schreibgeschützte Eigenschaft activeElement eines ShadowRoot liefert das Element innerhalb des Schattenbaums, das aktuell den Tastatur-Fokus besitzt. Sie ist das Gegenstück zu document.activeElement, wirkt aber nur auf den jeweiligen Shadow DOM.
Wegen der Kapselung (Retargeting) meldet document.activeElement bei einem fokussierten Element im Shadow DOM nur den Host der Web Component, also z. B. <my-input>, und nicht das eigentliche <input> darin. Um das tatsächlich fokussierte innere Element zu finden, fragt man shadowRoot.activeElement ab. Bei verschachtelten Komponenten muss man sich rekursiv durch die Schattenbäume nach unten arbeiten.
Typische Anwendungsfälle sind Fokusverwaltung in Web Components (Tastaturnavigation, Roving Tabindex, Fokusfallen in Dialogen), Barrierefreiheit und das Wiederherstellen des Fokus nach einem Neurendern.
Liegt der Fokus außerhalb dieses Schattenbaums, ist der Wert null. Befindet sich das fokussierte Element in einem verschachtelten Schattenbaum, liefert die Eigenschaft den Host dieses inneren Baums, der im aktuellen Baum liegt.
Rückgabewert
Element im Schattenbaum (bzw. der Host eines verschachtelten Schattenbaums, der den Fokus enthält) oder null, wenn der Fokus nicht in diesem Schattenbaum liegt.Beispiele
Fokussiertes Element innerhalb einer Web Component ermitteln
class LoginForm extends HTMLElement {
constructor() {
super();
const root = this.attachShadow({ mode: 'open' });
root.innerHTML = `
<input id="user" placeholder="Benutzer">
<input id="pass" type="password" placeholder="Passwort">
`;
}
}
customElements.define('login-form', LoginForm);
const form = document.createElement('login-form');
document.body.append(form);
form.shadowRoot.querySelector('#pass').focus();
console.log(document.activeElement.tagName); // Host
console.log(form.shadowRoot.activeElement.id); // tatsächliches Element
Tief verschachtelten Fokus rekursiv auflösen
// Liefert das wirklich fokussierte Element über alle Shadow-Grenzen hinweg
const getDeepActiveElement = (root = document) => {
let active = root.activeElement;
while (active?.shadowRoot?.activeElement) {
active = active.shadowRoot.activeElement;
}
return active;
};
document.addEventListener('focusin', () => {
const el = getDeepActiveElement();
console.log('Fokus auf:', el?.tagName, el?.id);
});
Fokus nach Neurendern wiederherstellen
class TodoList extends HTMLElement {
#root = this.attachShadow({ mode: 'open' });
items = ['Einkaufen', 'Putzen'];
connectedCallback() { this.render(); }
render() {
// ID des fokussierten Elements merken
const focusedId = this.#root.activeElement?.id;
this.#root.innerHTML = this.items
.map((t, i) => `<button id="item-${i}">${t}</button>`)
.join('');
if (focusedId) this.#root.getElementById(focusedId)?.focus();
}
}
customElements.define('todo-list', TodoList);
Prüfen, ob der Fokus in der Komponente liegt
const dialog = document.querySelector('my-dialog');
const hasFocusInside = dialog.shadowRoot.activeElement !== null;
console.log(hasFocusInside ? 'Fokus im Dialog' : 'Fokus außerhalb');
// Wichtig · Fallstricke
- Retargeting:
document.activeElementliefert nur den Shadow-Host. Für das echte Element immershadowRoot.activeElementverwenden – bei verschachtelten Komponenten rekursiv. - Geschlossene Schattenbäume: Bei
mode: 'closed'istelement.shadowRootnull. Nur die Komponente selbst kann über die beiattachShadow()gespeicherte Referenz aufactiveElementzugreifen. - Der Wert ist
null(nichtbodywie beidocument.activeElement), wenn kein Element im Schattenbaum fokussiert ist. - Die Eigenschaft ist schreibgeschützt; zum Fokussieren
element.focus()verwenden. MitdelegatesFocus: trueinattachShadow()wird der Fokus beim Klick auf den Host automatisch an das erste fokussierbare innere Element weitergereicht. - Die CSS-Pseudoklasse
:focus-withinauf dem Host ist oft eine einfachere Alternative, wenn nur das Styling angepasst werden soll. - Kompatibilität: in Chrome, Edge, Firefox und Safari unterstützt; die Eigenschaft ist in der Spezifikation über das Mixin
DocumentOrShadowRootdefiniert.