Signatur
Beschreibung
Das Ereignis beforeinput wird ausgelöst, bevor der Browser den Inhalt eines bearbeitbaren Elements verändert. Dazu gehören <input>, <textarea> und alle Elemente mit contenteditable. Der Handler bekommt ein InputEvent. Es sagt, was passieren soll (inputType, z. B. "insertText", "deleteContentBackward", "insertFromPaste") und welche Daten eingefügt werden (data bzw. dataTransfer).
Anders als das Ereignis input, das erst nach der Änderung kommt, lassen sich die meisten beforeinput-Ereignisse mit event.preventDefault() abbrechen. Damit kann man Eingaben filtern (z. B. nur Ziffern erlauben), Einfügen aus der Zwischenablage abfangen oder in Rich-Text-Editoren eigene Formatierungslogik umsetzen, ohne den DOM hinterher reparieren zu müssen.
Im Vergleich zu keydown ist beforeinput zuverlässiger: Es erfasst auch Eingaben über Einfügen, Ziehen und Ablegen, Autokorrektur, Spracheingabe und IME. Außerdem beschreibt es die beabsichtigte Bearbeitung, nicht die gedrückte Taste. Das Ereignis steigt im DOM auf (Bubbling), man kann es also per Ereignisdelegation an einem Elternelement abfangen. Mit event.getTargetRanges() erhält man in contenteditable-Elementen die betroffenen Bereiche als StaticRange-Objekte.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $type Pflicht | string | Name des Ereignisses: "beforeinput". Eine Property onbeforeinput gibt es in modernen Browsern ebenfalls, die Unterstützung ist aber uneinheitlicher als bei addEventListener. |
|
| $handler Pflicht | (event: InputEvent) => void | Callback-Funktion, die ein InputEvent erhält. Wichtige Eigenschaften: inputType, data, dataTransfer, isComposing, cancelable; Methode: getTargetRanges(). |
|
| $options | boolean | AddEventListenerOptions | false | Optionen wie capture, once, passive oder signal. Achtung: Mit passive: true hat preventDefault() keine Wirkung. |
Rückgabewert
addEventListener gibt nichts zurück. Den Standard kann der Handler über event.preventDefault() abbrechen, sofern event.cancelable den Wert true hat.Beispiele
Nur Ziffern in ein Eingabefeld zulassen
const plz = document.querySelector('#plz');
plz.addEventListener('beforeinput', (event) => {
// Löschen, Rückgängig usw. immer erlauben
if (!event.inputType.startsWith('insert')) return;
const text = event.data ?? event.dataTransfer?.getData('text/plain') ?? '';
if (/\D/.test(text)) {
event.preventDefault();
console.log(`Abgelehnt: "${text}" (${event.inputType})`);
}
});
Eingabetyp protokollieren und Listener mit AbortController entfernen
const editor = document.querySelector('[contenteditable]');
const controller = new AbortController();
editor.addEventListener('beforeinput', (event) => {
console.log(event.inputType, JSON.stringify(event.data));
}, { signal: controller.signal });
// Nach 10 Sekunden Protokollierung beenden
setTimeout(() => controller.abort(), 10_000);
Fett-Formatierung in einem Rich-Text-Editor verhindern (on-Property)
const editor = document.querySelector('#editor');
editor.onbeforeinput = (event) => {
if (event.inputType === 'formatBold' || event.inputType === 'formatItalic') {
event.preventDefault();
console.log('Formatierung ist hier nicht erlaubt.');
}
};
// Handler wieder entfernen
// editor.onbeforeinput = null;
Eingefügten Text vor dem Einfügen bereinigen
const textarea = document.querySelector('textarea');
textarea.addEventListener('beforeinput', (event) => {
if (event.inputType !== 'insertFromPaste') return;
event.preventDefault();
const raw = event.dataTransfer.getData('text/plain');
const clean = raw.replace(/\s+/g, ' ').trim();
// Bereinigten Text an der Cursorposition einfügen
textarea.setRangeText(clean, textarea.selectionStart, textarea.selectionEnd, 'end');
textarea.dispatchEvent(new Event('input', { bubbles: true }));
});
// Wichtig · Fallstricke
- Nicht immer abbrechbar: Während einer IME-Komposition (
event.isComposing === true, z. B. bei chinesischer oder japanischer Eingabe) sind Ereignisse wieinsertCompositionTextnicht abbrechbar. VorpreventDefault()daherevent.cancelableprüfen. - Browser-Unterschiede: Firefox unterstützt
beforeinputerst ab Version 87. WelcheinputType-Werte vorkommen und obgetTargetRanges()bei<input>/<textarea>Werte liefert (dort meist ein leeres Array), unterscheidet sich je nach Engine. Die WertehistoryUndo/historyRedosind nicht überall abbrechbar. - Keine Auslösung durch Skripte: Setzt man
element.valueper JavaScript, wird wederbeforeinputnochinputausgelöst. - Nicht bei jedem Eingabetyp: Bei
<select>, Checkboxen oder Radiobuttons wird keinbeforeinputausgelöst. datakannnullsein: Beim Löschen, Einfügen aus der Zwischenablage oder Ziehen und Ablegen stehen die Daten stattdessen indataTransfer.- Keine Sicherheitsprüfung: Ein Eingabefilter mit
beforeinputdient nur der Bedienbarkeit. Eingaben müssen immer zusätzlich auf dem Server geprüft werden. - Wer nach einem abgebrochenen Ereignis den Inhalt selbst ändert, sollte bei Bedarf ein
input-Ereignis manuell auslösen, damit Frameworks und Formularlogik davon erfahren.