iwantcoding.com
🔥 Daily 👥 Rooms 🏆 Top Log in Sign up

Two-way Bindings

Svelte bindings: bind:value for inputs, bind:this for DOM refs, bind:property for parent <-> child two-way. The little keyword that saves a lot of glue.

Svelte — bindings

EXAMPLE
<!-- ===== bind:value (forms) ===== -->
<script>
  let name = '';
  let age = 0;
  let bio = '';
  let agreed = false;
</script>

<input bind:value={name} placeholder="Name" />
<input type="number" bind:value={age} />
<textarea bind:value={bio}></textarea>
<input type="checkbox" bind:checked={agreed} />

<p>Hello, {name} ({age})</p>

<!-- ===== bind:this (DOM ref) ===== -->
<script>
  let inputEl;
  function focus() { inputEl?.focus(); }
</script>

<input bind:this={inputEl} />
<button on:click={focus}>Focus</button>

<!-- ===== bind:group (radio + checkbox groups) ===== -->
<script>
  let pick = 'sm';
  let toppings = [];
</script>

<label><input type="radio" bind:group={pick} value="sm" /> Small</label>
<label><input type="radio" bind:group={pick} value="md" /> Medium</label>
<label><input type="radio" bind:group={pick} value="lg" /> Large</label>
<p>Picked: {pick}</p>

<label><input type="checkbox" bind:group={toppings} value="cheese" /> Cheese</label>
<label><input type="checkbox" bind:group={toppings} value="pepperoni" /> Pepperoni</label>
<p>Toppings: {toppings.join(', ')}</p>

<!-- ===== bind:property (parent <-> child two-way) ===== -->
<!-- Child.svelte -->
<script>
  export let value = '';
</script>
<input bind:value placeholder="From parent" />

<!-- Parent.svelte -->
<script>
  import Child from './Child.svelte';
  let v = '';
</script>
<Child bind:value={v} />
<p>Parent sees: {v}</p>

<!-- The child can write to value AND parent stays in sync. -->
<!-- Use sparingly: explicit events are clearer for non-form parents. -->

<!-- ===== bind on media elements ===== -->
<script>
  let time = 0;
  let duration;
  let paused = true;
  let video;
</script>

<video bind:this={video} bind:currentTime={time} bind:duration bind:paused
       src="clip.mp4" controls></video>
<p>{time.toFixed(1)} / {duration?.toFixed(1)}s — {paused ? 'paused' : 'playing'}</p>

<!-- ===== bind on dimensions ===== -->
<script>
  let w, h;
</script>
<div bind:clientWidth={w} bind:clientHeight={h}>
  size: {w} x {h}
</div>

<!-- ===== bind on contenteditable ===== -->
<div contenteditable="true" bind:innerHTML={html}></div>

<!-- ===== When to use vs not =====
- bind: for forms; saves dozens of lines vs event handlers
- bind: between parent + child only when truly two-way
- Otherwise: props down + events up (clearer ownership)
-->

<!-- ===== Patterns to internalise =====
- bind:value for inputs (with .number / .trim modifiers in Svelte 5)
- bind:this for DOM/component refs needed for focus / measurement
- bind:group for radio + checkbox sets
- Media bindings (currentTime, duration, paused, volume) save controller code
-->

<!-- ===== Pitfalls =====
- bind on a parent prop the child should not own -> confusing data flow
- Two-way binding on derived state -> infinite loops
- contenteditable + bind:innerHTML with untrusted input -> XSS
- bind on a prop that does not exist on the child -> silent
-->

Why it matters

Bindings are Svelte cheat code for forms and component interop. bind:value, bind:this, bind:group, bind:property — small annotations that replace heaps of glue. Reach for them in form-heavy UIs; reach for explicit events when parent and child should not share ownership.

Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.

Example

Example
<input bind:value={name}>
<input type="checkbox" bind:checked={ok}>
Try it Yourself »

Discussion

Loading…