Signatur
Beschreibung
Der Konstruktor FocusEvent() erzeugt ein synthetisches Fokus-Ereignis. FocusEvent erbt von UIEvent und damit von Event. Zusätzlich gibt es die Eigenschaft relatedTarget: Das ist das Element, das den Fokus gerade verliert bzw. bekommt. Bei focusout ist es zum Beispiel das Element, zu dem der Fokus als Nächstes wandert.
Nützlich ist das vor allem in Unit- und Integrationstests, etwa mit jsdom, Testing Library oder im Browser. Dort löst man Fokus-Handler gezielt aus, ohne dass ein Mensch tabben oder klicken muss. Auch eigene Komponenten wie Web Components oder Dropdowns können so ihren Zustand weitergeben.
Wichtig: Ein mit dispatchEvent() ausgelöstes FocusEvent ruft nur die registrierten Handler auf. Das Element bekommt dadurch nicht wirklich den Fokus, und document.activeElement ändert sich nicht. Soll der Fokus tatsächlich wechseln, nimmt man element.focus() bzw. element.blur(). Diese Methoden lösen die echten Ereignisse selbst aus.
Standardmäßig blubbern selbst erzeugte Ereignisse nicht nach oben (bubbles: false). Das passt zu focus/blur. Für focusin/focusout, die in echt nach oben blubbern, sollte man bubbles: true ausdrücklich setzen.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $type Pflicht | string | Name des Ereignisses, üblicherweise "focus", "blur", "focusin" oder "focusout". Groß- und Kleinschreibung zählt. |
|
| $options | FocusEventInit | {} | Konfigurationsobjekt. Neben den Feldern aus UIEventInit (view, detail) und EventInit (bubbles, cancelable, composed) gibt es noch:
|
Rückgabewert
FocusEvent-Objekt. Man löst es mit target.dispatchEvent(event) aus.Beispiele
Einfaches focus-Ereignis erzeugen und auslösen
const input = document.querySelector('#email');
input.addEventListener('focus', (e) => {
console.log('Fokus-Handler:', e.type, e instanceof FocusEvent);
});
const evt = new FocusEvent('focus');
input.dispatchEvent(evt);
// Der echte Fokus hat sich NICHT geändert
console.log(document.activeElement === input);
focusout mit relatedTarget und bubbles für delegierte Handler
const form = document.querySelector('form');
const name = form.querySelector('#name');
const email = form.querySelector('#email');
// Delegierter Handler auf dem Formular: nur focusout blubbert
form.addEventListener('focusout', (e) => {
console.log(`${e.target.id} verlässt den Fokus -> ${e.relatedTarget?.id ?? 'nichts'}`);
});
name.dispatchEvent(new FocusEvent('focusout', {
bubbles: true,
relatedTarget: email
}));
Test: Validierung beim Verlassen eines Feldes (blur)
// z. B. in einem Vitest/Jest-Test mit jsdom
const input = document.createElement('input');
document.body.append(input);
const validate = (e) => {
e.target.classList.toggle('invalid', e.target.value.trim() === '');
};
input.addEventListener('blur', validate);
input.value = '';
input.dispatchEvent(new FocusEvent('blur'));
console.log(input.classList.contains('invalid'));
input.removeEventListener('blur', validate);
Eigenschaften eines erzeugten Ereignisses prüfen
const target = document.body;
const evt = new FocusEvent('focusin', {
bubbles: true,
composed: true,
relatedTarget: target
});
console.log(evt.type, evt.bubbles, evt.composed, evt.relatedTarget === target, evt.isTrusted);
// Wichtig · Fallstricke
- Kein echter Fokuswechsel:
dispatchEvent(new FocusEvent('focus'))ändert wederdocument.activeElementnoch:focus-Stile. Für einen echten Fokuswechsel nimmt manelement.focus(). - isTrusted: Selbst erzeugte Ereignisse haben immer
isTrusted === false. Code, der nur auf echte Nutzeraktionen reagieren soll, kann sie daran erkennen. - Blubbern: Echte
focus/blur-Ereignisse blubbern nicht,focusin/focusoutdagegen schon. Beim Konstruktor gilt immerbubbles: false, außer man setzt es ausdrücklich. - Shadow DOM: Soll das Ereignis über Shadow-Root-Grenzen hinweg sichtbar sein, braucht man
composed: true. Außerdem wirdrelatedTargetbeim Überqueren von Shadow-Grenzen umgeschrieben. - Kompatibilität: Der Konstruktor wird von allen modernen Browsern und von jsdom unterstützt. Im alten Internet Explorer gab es ihn nicht. Dort brauchte man das veraltete
document.createEvent('FocusEvent')mitinitFocusEvent(), und dieser Weg sollte heute nicht mehr verwendet werden. - Wird
typeweggelassen, wirft der Aufruf einenTypeError.