S SvelteKurs
M5 · Bindings & Formulare

Input-Bindings — bind:value & bind:checked

Formulareingaben direkt an reaktiven State koppeln — ohne einen einzigen Event-Handler von Hand zu schreiben.

Das Problem: zwei Richtungen

Ein Eingabefeld hat immer zwei Richtungen: Der State muss den angezeigten Wert bestimmen, und eine Eingabe des Nutzers muss den State aktualisieren. Ohne Hilfsmittel verdrahtest du beide von Hand — value hinein, oninput zurück:

svelte
<script>
  let name = $state('');
</script>

<!-- Ohne bind: musst du beide Richtungen selbst verdrahten -->
<input value={name} oninput={(e) => (name = e.currentTarget.value)} />
<p>Hallo, {name}!</p>

Das funktioniert, ist aber umständlich und fehleranfällig. Svelte bietet dafür bind:.

bind:value — Zwei-Wege-Bindung

bind:value verbindet ein Eingabefeld in beide Richtungen mit einer $state-Variable. Ändert sich der State, aktualisiert sich das Feld; tippt der Nutzer, aktualisiert sich der State.

svelte
<script>
  let name = $state('');
</script>

<!-- Mit bind:value erledigt Svelte beide Richtungen -->
<input bind:value={name} />
<p>Hallo, {name}!</p>

ℹ️ bind: ist nur Zucker

bind:value={name} ist exakt die Kurzform des vorigen Beispiels — Svelte setzt intern value={name} und einen oninput-Handler, der name zurückschreibt. Es passiert nichts Magisches: Es bleibt reaktiver State, den du auch anderswo lesen und setzen kannst.

Typ-Coercion bei number & range

Ein HTML-Eingabefeld liefert seinen Wert grundsätzlich als String. Bei type="number" und type="range" nimmt Svelte dir die Umwandlung ab und bindet automatisch eine echte Zahl — kein parseInt nötig.

svelte
<script>
  let alter = $state(0);
  let lautstaerke = $state(50);
</script>

<!-- type="number" und type="range" liefern automatisch Number, nicht String -->
<input type="number" bind:value={alter} />
<input type="range" min="0" max="100" bind:value={lautstaerke} />

<!-- alter ist wirklich eine Zahl: -->
<p>{alter + 1}</p>   <!-- 31, nicht "301" -->

⚠️ Ohne bind: bekommst du Strings

Nur bind:value übernimmt die Coercion. Liest du den Wert über einen eigenen oninput-Handler aus (e.currentTarget.value), erhältst du einen String — dann würde "30" + 1 zu "301" statt 31.

bind:checked — Checkboxen

Eine Checkbox hat keinen sinnvollen value, sondern einen Zustand „an/aus". Dafür gibt es bind:checked, das an einen boolean bindet:

svelte
<script>
  let einverstanden = $state(false);
</script>

<!-- bind:checked statt bind:value für Checkboxen -->
<label>
  <input type="checkbox" bind:checked={einverstanden} />
  AGB akzeptieren
</label>

{#if einverstanden}
  <button>Weiter</button>
{/if}

Live: Formular an ein State-Objekt binden

In der Praxis bündelst du mehrere Felder in einem $state-Objekt. Jedes Feld bindet an eine Eigenschaft — und das Objekt ist jederzeit ein exaktes Abbild des Formulars:

Profil.svelte svelte
<script>
  let profil = $state({
    name: '',
    alter: 0,
    bio: '',
    newsletter: false
  });
</script>

<input bind:value={profil.name} />
<input type="number" bind:value={profil.alter} />
<textarea bind:value={profil.bio}></textarea>
<input type="checkbox" bind:checked={profil.newsletter} />

<!-- profil ist jederzeit ein aktuelles Abbild des Formulars -->
<pre>{JSON.stringify(profil, null, 2)}</pre>
▶ Profil-Formular mit Live-Vorschau · Interaktiv

Live-Vorschau des $state-Objekts:

{
  "name": "Anna",
  "alter": 30,
  "bio": "Rails-Entwicklerin, neu bei Svelte.",
  "newsletter": true
}

Tippe oben — die Vorschau folgt bei jedem Tastendruck. Beachte: alter steht ohne Anführungszeichen da, ist also eine echte Zahl.

Rails-Vergleich: sofort statt nach dem Roundtrip

🛤️ form_with & params vs. bind:

In Rails leben Formularwerte auf dem Server: Der Nutzer füllt aus, drückt Submit, und erst der nächste Request liefert die Daten als params. Eine Live-Vorschau während des Tippens erfordert zusätzliches JavaScript (Stimulus, Turbo Frames o. Ä.).

Mit bind: ist der Zustand sofort im Browser verfügbar — ganz ohne Roundtrip. Das Absenden an einen Server ist ein separater, bewusster Schritt (Modul M9, Form Actions), nicht die Voraussetzung dafür, den Wert zu kennen.

Rails erb
# Rails: Werte reisen erst beim Submit als params zum Server
<%= form_with model: @profil do |f| %>
  <%= f.text_field :name %>
  <%= f.number_field :alter %>
  <%= f.text_area :bio %>
  <%= f.check_box :newsletter %>
  <%= f.submit %>
<% end %>

# Erst nach dem Roundtrip liegt params[:profil][:name] vor.
# Eine Live-Vorschau bräuchte zusätzlich Stimulus/Turbo + JS.

Zusammenfassung

💡 Das Wichtigste

  • bind:value koppelt Text-, Number-, Range- und Textarea-Felder in beide Richtungen.
  • bind:checked bindet Checkboxen an einen boolean.
  • bind: ist nur Zucker über value + oninput — kein eigener Handler nötig.
  • Bei type="number"/range bekommst du automatisch echte Zahlen.
  • Bündle mehrere Felder in einem $state-Objekt für sauberen Code.

🎯 Probier es selbst

Ergänze das Profil-Formular um ein Feld lautstaerke als <input type="range" min="0" max="100"> mit bind:value. Zeige den Wert daneben an und beobachte in der Vorschau, dass er als Zahl (nicht als String) erscheint.