Interaction and forms are how users change state; bindings remove most form boilerplate.
In Svelte 5 event handlers are just attributes whose names start with on: onclick={handler}, oninput={(e) => ...}, onsubmit={save}. If the handler variable has the same name, use the shorthand {onclick}.
There are no event modifiers any more (the old on:click|preventDefault syntax is legacy). Call e.preventDefault() yourself, or wrap handlers in a small helper. For capture, use onclickcapture. Svelte uses event delegation for common events like click and input: one listener at the root dispatches to your handlers, which is efficient but means e.stopPropagation() in a manually added listener can interfere.
Bindings create two-way links between DOM properties and state with bind::
bind:value={name}on inputs, textareas and selects (type="number"andrangegive numbers).bind:checked={agree}on checkboxes.bind:group={choice}on a set of radios (single value) or checkboxes (array of values).bind:this={el}gives you the DOM element (set after mount).- Read-only dimension bindings such as
bind:clientWidth={w}.
The shorthand bind:value binds to a variable called value. Bindings need a $state variable (or a bindable prop) on the other end. For custom conversion, Svelte 5.9+ supports function bindings: bind:value={() => get(), (v) => set(v)}.
Example
<script>
let name = $state('');
let age = $state(30);
let agree = $state(false);
let flavours = $state(['vanilla']);
let log = $state([]);
function onsubmit(e) {
e.preventDefault(); // no modifiers in Svelte 5
log.push(`${name} (${age}) ${flavours.join('+')}`);
}
</script>
<form {onsubmit}>
<input bind:value={name} placeholder="name" />
<input type="number" bind:value={age} /> <!-- age stays a number -->
{#each ['vanilla', 'chocolate'] as f}
<label><input type="checkbox" value={f} bind:group={flavours} /> {f}</label>
{/each}
<label><input type="checkbox" bind:checked={agree} /> I agree</label>
<button disabled={!agree}>Order</button>
</form>
<p>{log.join(', ')}</p>Remember
- Events are attributes:
onclick={fn}; calle.preventDefault()yourself bind:value,bind:checked,bind:groupkeep inputs and state in syncbind:thisgives the element once mounted
Watch out for
- Writing
onclick={doThing()}, which calls the function during render; passdoThingor() => doThing().