Bindings: bind
A binding connects the value of a form element with a variable in both directions: the user types — the variable changes, the code changes the variable — the field changes. It is shorter than writing a value attribute and an oninput handler by hand.
bind:value
<!-- src/routes/+page.svelte -->
<script>
let text = $state('');
</script>
<input bind:value={text} placeholder="New task" />
<p>You are typing: {text}</p>
<button onclick={() => (text = '')}>Clear</button>The paragraph repeats every typed letter, and the "Clear" button erases both the variable and the text in the field. Bind the value to a $state variable — otherwise the changes do not reach the rest of the markup.
Numbers
For type="number" and type="range" fields Svelte turns the string into a number itself:
<script>
let priority = $state(1);
</script>
<input type="number" bind:value={priority} min="1" max="5" />
<p>Priority × 2 = {priority * 2}</p>Type 3 — 6 appears below, not the string "33".
bind:checked
A checkbox is bound to a boolean:
<!-- src/routes/+page.svelte -->
<script>
let todos = $state([
{ id: 1, text: 'Buy bread', done: false },
{ id: 2, text: 'Call Oleg', done: true }
]);
let remaining = $derived(todos.filter((t) => !t.done).length);
</script>
{#each todos as todo (todo.id)}
<label>
<input type="checkbox" bind:checked={todo.done} />
{todo.text}
</label>
{/each}
<p>Left: {remaining}</p>Clicking a checkbox changes todo.done in the array right away, and the "Left" counter is recalculated. No onchange handler is needed.
bind:this
bind:this puts the DOM element itself into a variable. You need it when you must work with the element directly — for example, to put the cursor into a field:
<script>
let input;
$effect(() => {
input.focus();
});
</script>
<input bind:this={input} placeholder="New task" />When the page opens, the cursor is already in the field. The element appears in the variable only after the markup is rendered, so you use it in $effect or in handlers, not at the top of <script>.
Binding to a component prop
For a parent to write bind: on your component, the prop is marked with the $bindable rune:
<!-- src/lib/components/TodoInput.svelte -->
<script>
let { value = $bindable('') } = $props();
</script>
<input bind:value placeholder="New task" />Now in src/routes/+page.svelte you can write <TodoInput bind:value={text} />, and the parent's text variable changes as the user types. bind:value without braces is short for bind:value={value}.
Common mistake
Using value={text} instead of bind:value={text}. The field shows the initial value, but typing does not change the variable, and everything that depends on it stays the same. An attribute passes the value one way, bind: — both ways.