Die meisten Tutorials erklären „onclick” — und hören da auf. Reale Anwendungen brauchen aber Tastatur-Shortcuts, Drag-Verhalten, Touch-Gesten und kontrolliertes Focus-Management. Dieser Artikel geht durch alle wichtigen DOM-Event-Familien, immer mit einem Mini-Beispiel, das man auch mit wenig DOM-Erfahrung nachvollziehen kann.

Tastatur-Events – keydown, keyup, keypress

Wenn der Nutzer eine Taste drückt, gibt es drei Events in dieser Reihenfolge: keydown (Taste runter), keypress (eingegebenes Zeichen — gilt als veraltet) und keyup (Taste wieder hoch). In der Praxis nutzt man fast immer keydown.

svelte Beispiel: Eingabe analysieren
<script>
    let lastKey = $state('—');

    function handleKey(event) {
        lastKey = event.key;
    }
</script>

<input onkeydown={handleKey} placeholder="Tippe etwas …" />
<p>Zuletzt gedrückt: <strong>{lastKey}</strong></p>

Der Event hat zwei wichtige Eigenschaften:

  • event.key — was du als Mensch siehst: 'a', 'A', 'Enter', 'ArrowLeft', 'Escape'.
  • event.code — die physische Taste auf der Tastatur, unabhängig vom Layout: 'KeyA', 'Enter', 'ArrowLeft'. Nützlich für Spiele oder Shortcuts, die immer auf derselben Taste liegen sollen, egal ob US- oder DE-Layout.

Im Alltag reicht event.key.

Tastatur-Shortcuts (z. B. Cmd/Ctrl + S)

Praktisches Beispiel: „Speichern” mit Cmd+S oder Strg+S abfangen.

svelte Save-Shortcut
<script>
    function handleSaveShortcut(event) {
        const isSaveCombo = event.key === 's' && (event.metaKey || event.ctrlKey);
        if (!isSaveCombo) return;

        event.preventDefault(); // Browser-„Seite speichern"-Dialog verhindern
        console.log('App-eigenes Speichern auslösen');
    }
</script>

<svelte:window onkeydown={handleSaveShortcut} />

Drei Punkte zum Verstehen:

  1. metaKey ist ⌘ auf macOS, ctrlKey ist Strg auf Windows/Linux. Beides oder-verknüpft funktioniert plattformübergreifend.
  2. event.preventDefault() verhindert den Browser-Default — sonst würde der „Seite speichern”-Dialog aufgehen.
  3. <svelte:window> lauscht auf Window-Ebene — der Listener funktioniert, egal welches Element gerade Fokus hat.

Weitere Modifier-Tasten

EigenschaftBedeutung
event.shiftKeyUmschalt
event.altKeyAlt / Option
event.ctrlKeyStrg
event.metaKey⌘ (macOS) / Win-Taste (Windows)

Häufige Tasten-Werte

event.key als Vergleichswert ist string-basiert. Die wichtigsten Schlüsselwerte:

event.keyBedeutung
'Enter'Eingabetaste
'Escape'Esc
'Tab'Tab
'Backspace'Rückschritt
'Delete'Entf
'ArrowUp'/'ArrowDown'/'ArrowLeft'/'ArrowRight'Pfeiltasten
' ' (Leerzeichen)Space
'a'-'z', '0'-'9'Buchstaben/Zahlen
svelte Modal mit Escape schließen
<script>
    let { open = $bindable(false) } = $props();

    function handleKey(event) {
        if (event.key === 'Escape') open = false;
    }
</script>

{#if open}
    <svelte:window onkeydown={handleKey} />
    <div class="modal">…</div>
{/if}

Maus-Events – click, mousedown, mouseup, mousemove

click deckt 90 % aller Klicks ab. Wenn du vor dem Loslassen schon etwas tun willst (typisch bei Drag-Operationen), gibt es das feinere Geschwister-Trio:

  • mousedown — Maustaste gedrückt.
  • mousemove — Maus bewegt sich.
  • mouseup — Maustaste losgelassen.
svelte Drag-Beispiel (vereinfacht)
<script>
    let dragging = $state(false);
    let x = $state(0);
    let y = $state(0);

    function start() {
        dragging = true;
    }

    function move(event) {
        if (!dragging) return;
        x = event.clientX;
        y = event.clientY;
    }

    function stop() {
        dragging = false;
    }
</script>

<svelte:window onmousemove={move} onmouseup={stop} />

<div
    class="box"
    style="transform: translate({x}px, {y}px)"
    onmousedown={start}
>
    ziehe mich
</div>

Wichtig: mousemove und mouseup werden auf Window gehört, nicht auf der Box. Sonst verlierst du das Tracking, sobald die Maus die Box verlässt.

Position im Event

Das Event-Objekt hat mehrere Koordinaten-Paare:

  • clientX/clientY — relativ zum sichtbaren Browser-Fenster.
  • pageX/pageY — relativ zur gesamten Seite (mit Scroll).
  • offsetX/offsetY — relativ zum Element, auf dem das Event ausgelöst wurde.

In den meisten Fällen reicht clientX/clientY.

Pointer-Events – die moderne Vereinheitlichung

Smartphones und Tablets haben weder Maus noch Tastatur — sondern Touch und Stylus. Damit du nicht für jede Eingabeart eigene Handler schreiben musst, gibt es seit ein paar Jahren Pointer-Events: ein vereinheitlichter Mechanismus für Maus, Touch und Stift.

Maus-EventPointer-Äquivalent
mousedownpointerdown
mousemovepointermove
mouseuppointerup
mouseenterpointerenter
mouseleavepointerleave

Empfehlung: Bei neuem Code Pointer-Events nutzen. Der gleiche Code funktioniert dann automatisch mit Touch-Geräten.

svelte Drag mit Pointer-Events
<script>
    let x = $state(0);
    let y = $state(0);

    function startDrag(event) {
        event.target.setPointerCapture(event.pointerId);
    }

    function drag(event) {
        if (!event.buttons) return; // nur wenn gedrückt
        x = event.clientX;
        y = event.clientY;
    }
</script>

<div
    class="handle"
    style="transform: translate({x}px, {y}px)"
    onpointerdown={startDrag}
    onpointermove={drag}
>
    zieh mich
</div>

setPointerCapture(event.pointerId) ist der Trick, der das Drag „klebrig” macht: Auch wenn der Pointer das Element verlässt, kommen weiterhin pointermove-Events bei diesem Element an. Kein Window-Listener mehr nötig.

Welche Eingabeart war es?

Pointer-Events tragen die Information mit:

svelte event.pointerType
<div onpointerdown={(e) => console.log(e.pointerType)}>

</div>

event.pointerType ist 'mouse', 'touch' oder 'pen'.

Touch-Events (selten, aber manchmal nötig)

Wenn dein Code wirklich nur auf Touch-Geräten laufen muss oder du Multi-Touch brauchst (zwei Finger gleichzeitig), gibt es noch die klassischen Touch-Events: touchstart, touchmove, touchend. Sie liefern eine touches-Liste mit allen aktuell aktiven Finger-Positionen.

svelte Pinch-Zoom (Skizze)
<script>
    function handleTouch(event) {
        if (event.touches.length === 2) {
            const [a, b] = event.touches;
            const distance = Math.hypot(b.clientX - a.clientX, b.clientY - a.clientY);
            console.log('Zwei Finger, Abstand:', distance);
        }
    }
</script>

<div ontouchmove={handleTouch}>

</div>

Für die meisten Anwendungen reichen Pointer-Events vollkommen aus.

Focus-Events – focus, blur, focusin, focusout

Wenn ein Eingabefeld den Fokus bekommt oder verliert, kannst du mit focus/blur reagieren:

svelte Auto-Highlight bei Focus
<script>
    function selectAll(event) {
        event.target.select();
    }
</script>

<input value="Doppelklick auf mich" onfocus={selectAll} />

Der wichtige Unterschied: focus vs. focusin

focus und blur bubblen nicht — sie feuern nur am direkt fokussierten Element. Wenn du auf einem Eltern-Element wissen willst, ob irgendein Kind den Fokus hat, brauchst du focusin und focusout (die bubblen).

svelte Container mit Focus-Indikator
<script>
    let hasFocus = $state(false);
</script>

<div
    class="form-group"
    class:active={hasFocus}
    onfocusin={() => hasFocus = true}
    onfocusout={() => hasFocus = false}
>
    <input />
    <button>OK</button>
</div>

<style>
    .form-group.active { border-color: teal; }
</style>

Egal ob <input> oder <button> Fokus hat — die <div> weiß es.

Click-Outside-Pattern (häufig nachgefragt)

Eines der meist gefragten Patterns: „Ein Dropdown soll sich schließen, wenn der Nutzer außerhalb klickt.” Das geht so:

svelte Dropdown.svelte
<script>
    let open = $state(false);
    let container;

    function handleWindowClick(event) {
        if (open && !container.contains(event.target)) {
            open = false;
        }
    }
</script>

<svelte:window onclick={handleWindowClick} />

<div bind:this={container}>
    <button onclick={() => open = !open}>Menü</button>

    {#if open}
        <ul class="menu">
            <li>Eintrag 1</li>
            <li>Eintrag 2</li>
        </ul>
    {/if}
</div>

Schritt für Schritt:

  1. Der Window-Listener fängt jeden Klick auf der Seite ab.
  2. container.contains(event.target) prüft, ob der Klick innerhalb des Dropdown-Containers war.
  3. Wenn nicht (außerhalb), wird das Dropdown geschlossen.

Eleganter als manuelles Listener-Verwalten — und voll reaktiv.

Häufige Stolperfallen

event.preventDefault() zu spät aufgerufen. Bei onsubmit und onkeydown muss preventDefault() synchron gerufen werden — nicht erst in einem await-Callback. Sonst ist es zu spät.

focus und blur mit Bubbling erwartet. Sie bubblen nicht. Für Container-übergreifendes Tracking brauchst du focusin/focusout.

mouseup außerhalb des Elements verloren. Wenn die Maus das Element verlässt, bevor losgelassen wird, kommt das mouseup nicht mehr an. Lösung: Listener auf <svelte:window> legen oder Pointer-Events mit setPointerCapture.

Tastatur-Shortcuts in Inputs. Wenn der Nutzer im Input tippt, willst du Shortcuts oft nicht abfangen. Prüfen mit event.target.tagName === 'INPUT' oder document.activeElement.

Modifier-Keys vergessen. Wer einen Save-Shortcut nur auf event.key === 's' prüft, fängt jedes „s” beim Tippen. Immer zusätzlich auf metaKey/ctrlKey prüfen.

Weiterführende Ressourcen

Externe Quellen

Verwandte Artikel

/ Weiter

Zurück zu Events

Zur Übersicht