bind: ist eines der charakteristischsten Konstrukte in Svelte: Es verbindet einen reaktiven Wert direkt mit einem DOM-Property oder einer Komponenten-Prop, sodass beide automatisch synchron bleiben — ohne manuell value= und oninput= zu schreiben. Dieser Artikel gibt die Übersicht über alle verfügbaren Bindings, unterscheidet zwischen Two-Way- und Read-only-Bindings und zeigt, wann ein Binding gegenüber einem klassischen Event-Handler die elegantere Wahl ist.
Was macht bind:?
Ohne Binding schreibst du klassisch zwei Stellen — eine zum Lesen, eine zum Reagieren auf Änderungen:
<script>
let name = $state('');
</script>
<input value={name} oninput={(e) => name = e.currentTarget.value} />Mit bind:value reicht eine Direktive — Svelte macht beides automatisch:
<input bind:value={name} />bind: ist syntaktischer Zucker für die Two-Way-Synchronisierung zwischen einer Variablen und einem DOM-Property.
Two-Way- vs. Read-only-Bindings
Nicht jedes Binding lässt sich von beiden Seiten beschreiben:
- Two-Way:
bind:value,bind:checked,bind:files,bind:open,bind:currentTime— du kannst lesen und schreiben. - Read-only:
bind:clientWidth,bind:duration,bind:naturalWidthetc. — du kannst nur lesen. Diese Werte werden vom Browser bestimmt; ein Schreibversuch wird ignoriert.
Read-only-Bindings sind trotzdem reaktiv: Wenn der Browser den Wert ändert (z. B. weil sich die Fenstergröße ändert), wird die Variable im Script aktualisiert.
Übersicht aller Bindings
Form-Elemente
| Binding | Element | Richtung | Wert-Typ |
|---|---|---|---|
bind:value | input, textarea, select | Two-Way | string/number/array |
bind:checked | checkbox, radio | Two-Way | boolean |
bind:indeterminate | checkbox | Two-Way | boolean |
bind:group | radio, checkbox | Two-Way | string/array |
bind:files | input[type=file] | Two-Way | FileList |
Media-Elemente (audio, video)
| Binding | Richtung | Beschreibung |
|---|---|---|
bind:currentTime | Two-Way | Aktuelle Wiedergabe-Position |
bind:playbackRate | Two-Way | Geschwindigkeit |
bind:paused | Two-Way | Pause-Zustand |
bind:volume | Two-Way | Lautstärke (0–1) |
bind:muted | Two-Way | Stumm |
bind:duration | Read-only | Gesamtdauer |
bind:buffered | Read-only | Gepufferte Bereiche |
bind:seekable | Read-only | Seekbare Bereiche |
bind:seeking | Read-only | Aktuell am Seeken |
bind:ended | Read-only | Wiedergabe beendet |
bind:readyState | Read-only | Ladezustand |
bind:played | Read-only | Bereits abgespielte Bereiche |
Für <video> zusätzlich:
| Binding | Richtung | Beschreibung |
|---|---|---|
bind:videoWidth | Read-only | Native Videobreite |
bind:videoHeight | Read-only | Native Videohöhe |
Bilder
| Binding | Richtung | Beschreibung |
|---|---|---|
bind:naturalWidth | Read-only | Native Bildbreite |
bind:naturalHeight | Read-only | Native Bildhöhe |
Block-Level (Größen)
Auf jedem HTML-Element verfügbar:
| Binding | Richtung | Beschreibung |
|---|---|---|
bind:clientWidth | Read-only | Sichtbare Breite ohne Scrollbar |
bind:clientHeight | Read-only | Sichtbare Höhe |
bind:offsetWidth | Read-only | Außenmaß inkl. Border |
bind:offsetHeight | Read-only | Außenhöhe |
bind:contentRect | Read-only | DOMRect aus ResizeObserver |
bind:contentBoxSize | Read-only | Content-Box-Maße |
bind:borderBoxSize | Read-only | Border-Box-Maße |
bind:devicePixelContentBoxSize | Read-only | Pixel-genaue Content-Box |
Diese werden intern von einem ResizeObserver versorgt — kein eigener Listener nötig.
Spezielle Elemente
| Binding | Element | Richtung |
|---|---|---|
bind:open | <details> | Two-Way |
bind:innerHTML | contenteditable | Two-Way |
bind:innerText | contenteditable | Two-Way |
bind:textContent | contenteditable | Two-Way |
Refs
| Binding | Beschreibung |
|---|---|
bind:this | Referenz auf DOM-Knoten oder Komponenten-Instanz |
Komponenten
| Binding | Richtung | Anforderung |
|---|---|---|
bind:propertyName | Two-Way | Prop muss $bindable() sein |
Bindings sind reaktiv
Das Schöne: Sobald die gebundene Variable mit $state reaktiv ist, wirken Updates in beide Richtungen — und alle abgeleiteten Werte aktualisieren sich automatisch:
<script>
let name = $state('');
let charCount = $derived(name.length);
</script>
<input bind:value={name} />
<p>{charCount} Zeichen</p>Bei jeder Eingabe aktualisiert sich name (Browser -> Variable), und charCount (Variable -> UI) berechnet sich neu.
Wann bind:, wann manuell?
| Situation | Empfehlung |
|---|---|
| Reine Synchronisation Variable ↔ DOM | bind: |
| Validierung beim Eingeben | manueller oninput-Handler |
| Throttling oder Debouncing | manueller Handler oder Custom-Hook |
| Logging / Analytics bei Änderung | manueller Handler |
| Lese-Zugriff auf Browser-Werte | Read-only-bind: (z. B. Größen, Media) |
Sobald Logik beim Update gefragt ist, liefert ein expliziter Event-Handler mehr Kontrolle. Für reine Form-Felder ohne Logik ist bind: aber unschlagbar kompakt.
Bindings und Reaktivität — wichtiges Detail
Damit bind: funktioniert, muss die Ziel-Variable reaktiv sein. Ein nacktes let reicht in Svelte 5 nicht:
<script>
let value = ''; // kein $state
</script>
<input bind:value /> <!-- Funktioniert nur eingeschränkt --><script>
let value = $state('');
</script>
<input bind:value />Im Legacy-Modus (Svelte 4) waren let-Variablen automatisch reaktiv — in Svelte 5 mit Runes ist $state Pflicht.
Beispiel: Live-Vorschau eines Eingabefelds
<script>
let title = $state('Mein Beitrag');
let body = $state('');
</script>
<form>
<label>
Titel
<input bind:value={title} />
</label>
<label>
Inhalt
<textarea bind:value={body} rows="4"></textarea>
</label>
</form>
<article>
<h1>{title || '(ohne Titel)'}</h1>
<p>{body || '(noch leer)'}</p>
</article>Eingabe links, Vorschau rechts — kein einziger Event-Handler, nichts zum Vergessen.
Häufige Stolperfallen
Bind ohne reaktive Variable.
bind:value={value} mit nicht-$state-Variable führt zu seltsamem Verhalten oder Compiler-Warnung.
Bind auf abgeleiteten Wert.
bind:value={fullName} mit fullName als $derived geht nicht — abgeleitete Werte sind nicht beschreibbar.
Konflikt zwischen bind:value und value=....
Beides gleichzeitig zu setzen führt zu undefiniertem Verhalten. Entweder bind: oder manuelle Steuerung — nicht beides.
Numerische Inputs liefern Strings.
<input type="number"> gibt mit bind:value automatisch eine Zahl zurück — keine Konvertierung nötig. Bei type="text" mit numerischer Eingabe ist es weiterhin ein String.
Bind auf Komponenten-Property ohne $bindable.
Compiler-Fehler. Die Prop muss in der Kind-Komponente explizit als bindbar markiert sein — siehe $bindable.