How-To

How-To · Reactivity

How to Bind an Input with bind:value in Svelte

Bind a text input to state in Svelte: declare a reactive variable, add bind:value to the input so typing updates it automatically, then read and display the value — two-way binding with no event handler.

XCODXHow-To · Updated

Overview

The simplest way to read what a user types in Svelte is the bind:value directive. It creates a two-way binding between an input and a variable: type in the field and the variable updates, change the variable and the field follows. Unlike React, you do not pair a value attribute with an onChange handler — a single bind:value does both directions. You need this whenever you want to read, validate, or react to input as the user types, which is almost every form. The approach is three small moves: declare a reactive variable, bind it to the input, then read and display it.

Steps

1. Declare a reactive variable

Every bound input needs a variable to hold its value. Declare a top-level let in your component's <script>, giving it a sensible starting value — an empty string for a text field. Because it is a top-level let that the markup will read, it is reactive automatically: no wrapper, no hook. This variable is the single source of truth for what the field contains.

<script>
  let name = '';
</script>

2. Add bind:value to the input

Connect the variable to the input with the bind:value={name} directive. This is what makes the binding two-way: the input displays exactly what is in name, and any keystroke assigns the new text back into name for you. On the first render the field shows the empty string you initialised, and from then on the field and the variable stay mirrored — no separate change handler required.

<input bind:value={name} placeholder="Your name" />

3. It updates automatically as you type

There is no third wiring step for the update itself — that is the point of the directive. Each keystroke assigns the new value into name, and because assignment is what drives Svelte reactivity, everything that reads name re-renders. A $: statement that references it re-runs, and any markup showing it redraws. The tight loop of type, assign, re-render happens on your behalf. The same shape covers other controls — a group of radios binds to one variable with bind:group:

<script>
  let size = 'medium';
</script>

<label><input type="radio" bind:group={size} value="small" /> Small</label>
<label><input type="radio" bind:group={size} value="medium" /> Medium</label>
<label><input type="radio" bind:group={size} value="large" /> Large</label>

<p>Selected: {size}</p>

4. Read and display the value

Because the current value is always sitting in your variable, reading it is just interpolation — put {name} anywhere in the markup and it tracks every change. There is nothing to query from the DOM and no submit-time lookup needed; the variable already holds exactly what the user sees. Derive from it freely, for example a character count with $: length = name.length.

<p>You typed: {name}</p>

Runnable example

Here are all three moves together — a text input bound with bind:value that echoes the typed text live below the field. Type in it and watch the echo track each keystroke, then open it in the editor:

The echo and the character count both read straight from name, which is why they update on every keystroke. The same directive works beyond text: bind:checked binds a checkbox, bind:value on a <select> binds a dropdown, and bind:group binds radio buttons — each wiring state to the control in both directions. This second demo binds a checkbox and a select and drives a live summary line from them:

Common pitfalls

<script>
  let age = 0;
</script>

<input type="number" bind:value={age} />
<p>Next year you will be {age + 1}</p>

One more note: initialise the variable to a matching empty value — '' for text — rather than leaving it undefined. Starting undefined can render the literal text undefined in the field before the first keystroke.

Frequently asked questions

What does bind:value do in Svelte?
It creates a two-way binding between an input and a variable: the input shows the variable's value, and typing assigns the new value back into the variable. It replaces the manual value-plus-onChange pairing other frameworks require.
Do I need an onChange handler with bind:value?
No. bind:value handles both directions itself, so a separate change handler is unnecessary. Each keystroke assigns into your variable automatically, and Svelte's assignment-driven reactivity re-renders anything that reads it.
Why is my Svelte input not updating my variable?
You most likely wrote value={name} instead of bind:value={name}. A plain value attribute displays the value but does not bind it, so typing changes nothing. Add the bind: prefix to make it two-way.
How do I bind a checkbox or select in Svelte?
Use bind:checked on a checkbox, bind:value on a <select>, and bind:group for radio buttons. Each binds the control to a variable in both directions, the same way bind:value binds a text input.