Bindings and Events

Chapter 4
Bindings and Events
Two-way binding with bind:, event handlers, and the class:/style: directives

With reactivity covered, this chapter connects it to the DOM: handling events, two-way-binding form inputs, and toggling classes/styles conditionally. Svelte leans toward standard HTML here — event handlers are plain DOM attributes — with a few concise directives layered on top.

Event Handlers

<script> let count = $state(0); </script> <button onclick={() => count++}>+1</button> <input oninput={handleInput} />

In Svelte 5, events are just standard lowercase DOM attributes — onclick, oninput, onsubmit — set to a function. onclick={() => count++} uses an inline arrow; oninput={handleInput} passes a function reference. This is closer to plain HTML than any of the other frameworks (which all use their own syntax — onClick in React, (click) in Angular, @click in Vue). The native event object is the handler's argument, exactly as in vanilla JS.

Svelte 4 used on:click — Svelte 5 uses onclick
Pre-Svelte-5 code used a directive form with a colon: on:click={handler}. Svelte 5 replaced it with the plain DOM-attribute form onclick={handler} (no colon), aligning with standard HTML. Both may appear during the transition, but onclick is the modern style this course uses. The on: version is the giveaway for older code.

bind: — Two-Way Binding

<script> let name = $state(''); </script> <input bind:value={name} /> <p>Hello, {name}!</p>

bind:value={name} keeps a form input and a $state variable synchronized in both directions — typing updates name, and changing name in code updates the input. This is Svelte's equivalent of Vue's v-model and Angular's [(ngModel)], and it collapses React's manual value + onChange controlled-input pattern into one directive. The bind: prefix marks a two-way binding (vs a one-way attribute).

bind: on Different Input Types

<input type="checkbox" bind:checked={agreed} /> <!-- boolean --> <input type="number" bind:value={age} /> <!-- auto-coerced to a number --> <select bind:value={country}> <!-- string --> <option value="ie">Ireland</option> <option value="hu">Hungary</option> </select>

Like Vue's v-model, Svelte's bind: adapts to the input type — checkboxes use bind:checked (a boolean), a <select> binds to the chosen option's value, and a type="number" input even auto-coerces the value to a number for you (a small nicety React makes you do by hand). Same simplicity benefit as Vue over React's per-type handling.

class: — Toggling a Class

<div class:active={isActive}>...</div> <!-- shorthand when the variable name matches the class name --> <div class:active>...</div>

class:active={isActive} adds the active class when isActive is truthy and removes it otherwise — a clean, declarative toggle, the equivalent of Angular's [class.active] and Vue's class binding. When the variable name matches the class name, you can shorten it to just class:active. Multiple class: directives can sit on one element.

style: — Binding a Style Property

<p style:color={isError ? 'red' : 'black'}>...</p> <div style:width={`${progress}%`}>...</div>

style:color={...} binds a single inline style property to a reactive expression — handy for values that change dynamically, like a progress bar's width or a conditional color. The parallel of Angular's [style.color], expressed as a directive.

Form Submission

<script> let value = $state(''); function handleSubmit(e) { e.preventDefault(); console.log(value); value = ''; } </script> <form onsubmit={handleSubmit}> <input bind:value={value} /> <button>Submit</button> </form>

Svelte uses the standard onsubmit handler and standard e.preventDefault() — no special "prevent" modifier like Vue's @submit.prevent. Because bind:value keeps value in sync, the handler reads the current value directly and clears it by reassigning, with reactivity handling the rest.

SvelteVueAngularReact
onclick={fn}@click="fn"(click)="fn()"onClick={fn}
bind:value={x}v-model="x"[(ngModel)]="x"value + onChange
class:active={x}class binding[class.active]conditional className
style:color={x}:style[style.color]style={{}}

Coding Challenges

Challenge 1

Build a counter with +1/-1/reset buttons using onclick handlers (inline arrows are fine), displaying the $state count.

📄 View solution
Challenge 2

Build a form with a text input (bind:value), a checkbox (bind:checked), and a select (bind:value), each bound to its own $state variable, displaying all three values live below the form.

📄 View solution
Challenge 3

Build a "toggle" component: a button that flips an isOn $state boolean, a div whose active class is toggled with class:active={isOn}, and a style:background bound to a color that changes based on isOn.

📄 View solution

Chapter 4 Quick Reference

  • onclick={fn} — standard lowercase DOM event attributes (Svelte 5; was on:click in v4)
  • bind:value={x} — two-way binding (= v-model / [(ngModel)]); no import needed
  • bind: adapts to type: bind:checked (boolean), type="number" auto-coerces
  • class:active={x} — toggle a class; shorthand class:active when names match
  • style:prop={x} — bind a single inline style property
  • Forms use standard onsubmit + e.preventDefault() — no special modifier
  • Next chapter: conditional and list rendering — {#if}, {#each}, {#await}