Skip to content

Commit 1e697d3

Browse files
committed
event docs
1 parent 82cf973 commit 1e697d3

File tree

1 file changed

+178
-1
lines changed

1 file changed

+178
-1
lines changed

sites/svelte-5-preview/src/routes/docs/content/01-api/04-event-handlers.md

Lines changed: 178 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,181 @@
22
title: Event handlers
33
---
44

5-
To add an event listener to an element, add the corresponding `on` property:
5+
Event handlers have been given a facelift in Svelte 5. Whereas in Svelte 4 we use the `on:` directive to attach an event listener to an element, in Svelte 5 they are properties like any other:
6+
7+
```diff
8+
<script>
9+
let count = $state(0);
10+
</script>
11+
12+
-<button on:click={() => count++}>
13+
+<button onclick={() => count++}>
14+
clicks: {count}
15+
</button>
16+
```
17+
18+
Since they're just properties, you can use the normal shorthand syntax...
19+
20+
```svelte
21+
<script>
22+
let count = $state(0);
23+
24+
function onclick() {
25+
count++;
26+
}
27+
</script>
28+
29+
<button {onclick}>
30+
clicks: {count}
31+
</button>
32+
```
33+
34+
...though when using a named event handler function it's usually better to use a more descriptive name.
35+
36+
Traditional `on:` event handlers will continue to work, but are deprecated in Svelte 5.
37+
38+
## Component events
39+
40+
In Svelte 4, components could emit events by creating a dispatcher with [`createEventDispatcher`](https://svelte.dev/docs/svelte#createeventdispatcher).
41+
42+
This function is deprecated in Svelte 5. Instead, components should accept _callback props_ ([demo](/#H4sIAAAAAAAAE41TS27bMBC9yoBtELu1Pg6gBlAkob1B91UXijSKiVAkIdJ2XEH7rrroBbrq_XqEkBTlD-JFFxLIx_fecIYzA2kpQ0XSbwPhVYckJV-kJCuiD9Ju1A6ZRrNXYtvXFslU3VOpi5KXmnZS9Bq-bjsJbS86uA0juwkn2e2DJdmPoQZFfyDk8F7pSuNinSzNaRad3Hhmpc6Wt8xw8mGxhLyAwblop_-YQzK5atrCwmEF3CfL2T52p-No_w1e8znTrWddMNtaYeRuM7wzxImXG6IzzJSsONSsUiovyWPFmBC8JKD0gaFBVF0xTGGIw3gNH5x6LEnx78-vnyZTozXOQ4pM4TU7ITpH_v33RI5oO7rauBCu6E7kc5FCUU0FT6GlL9j4yjBsdeorUWot5Gmzp43epLCO4xuPbJA-bfQF1AquA3t5h-72sxG-6KBi9MmEq5Fr7Od4lGNw9HmYr0YtJcCdoaoUuOA4ldjmU-rQl29ORfcVn5NxdYQ4vFOXClOhmV5x2lUT28FxmChoRb-v-uZC9fkZD21vWlvBuT6-gQH8e8XhJxgn-C65wO-T-cCW5-xkgkfXwf5lzJB0oqEtxYakut_iuDrOlO3s_x0qOysD-BlYgW9iGO3syF5ItXg7OQ3dHftI2ikizip73Jrn5yB4zWj9nA_edSz8IosmxnW2Dz0WfnHGziITsnib8vfxFf2EUSRSBAAA)):
43+
44+
```svelte
45+
<script>
46+
import Pump from './Pump.svelte';
47+
48+
let size = $state(15);
49+
</script>
50+
51+
<Pump
52+
inflate={() => {
53+
size += 5;
54+
if (size > 75) size = 0;
55+
}}
56+
deflate={() => {
57+
if (size > 15) size -= 5;
58+
}}
59+
/>
60+
61+
{#if size >= 15}
62+
<span class="balloon" style="scale: {0.01 * size}">
63+
🎈
64+
</span>
65+
{:else}
66+
<span class="boom"> 💥 </span>
67+
{/if}
68+
```
69+
70+
```svelte
71+
<script>
72+
let { inflate, deflate } = $props();
73+
</script>
74+
75+
<div class="pump">
76+
<button onclick={inflate}>inflate</button>
77+
<button onclick={deflate}>deflate</button>
78+
</div>
79+
```
80+
81+
## Bubbling events
82+
83+
Instead of doing `<button on:click>` to 'forward' the event from the element to the component, the component should accept an `onclick` callback prop:
84+
85+
```svelte
86+
<script>
87+
let { onclick, children } = $props();
88+
</script>
89+
90+
<button {onclick}>
91+
{@render children()}
92+
</button>
93+
```
94+
95+
Note that this also means you can 'spread' event handlers onto the element along with other props:
96+
97+
```svelte
98+
<script>
99+
let { children, ...props } = $props();
100+
</script>
101+
102+
<button {...props}>
103+
{@render children()}
104+
</button>
105+
```
106+
107+
## Event modifiers
108+
109+
In Svelte 4, you can add event modifiers to handlers:
110+
111+
```svelte
112+
<button on:click|once|preventDefault={handler}>...</button>
113+
```
114+
115+
Modifiers are specific to `on:` and as such do not work with modern event handlers. Adding things like `event.preventDefault()` inside the handler itself is preferable, since all the logic lives in one place rather than being split between handler and modifiers.
116+
117+
Since event handlers are just functions, you can create your own wrappers as necessary:
118+
119+
```svelte
120+
<script>
121+
function once(fn) {
122+
return function (event) {
123+
if (fn) fn.call(this, event);
124+
fn = null;
125+
};
126+
}
127+
128+
function preventDefault(fn) {
129+
return function (event) {
130+
event.preventDefault();
131+
fn.call(this, event);
132+
};
133+
}
134+
</script>
135+
136+
<button onclick={once(preventDefault(handler))}>...</button>
137+
```
138+
139+
There are three modifiers — `capture`, `passive` and `nonpassive` — that can't be expressed as wrapper functions, since they need to be applied when the event handler is bound rather than when it runs.
140+
141+
For `capture`, we add the modifier to the event name:
142+
143+
```svelte
144+
<button onclickcapture={...}>...</button>
145+
```
146+
147+
Changing the [`passive`](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#using_passive_listeners) option of an event handler, meanwhile, is not something to be done lightly. If you have a use case for it — and you probably don't! - then you will need to use an action to apply the event handler yourself.
148+
149+
## Multiple event handlers
150+
151+
In Svelte 4, this is possible:
152+
153+
```svelte
154+
<button on:click={one} on:click={two}>...</button>
155+
```
156+
157+
This is something of an anti-pattern, since it impedes readability (if there are many attributes, it becomes harder to spot that there are two handlers unless they are right next to each other) and implies that the two handlers are independent, when in fact something like `event.stopImmediatePropagation()` inside `one` would prevent `two` from being called.
158+
159+
Duplicate attributes/properties on elements — which now includes event handlers — are not allowed. Instead, do this:
160+
161+
```svelte
162+
<button
163+
onclick={(e) => {
164+
one(e);
165+
two(e);
166+
}}
167+
>
168+
...
169+
</button>
170+
```
171+
172+
## Why the change?
173+
174+
By deprecating `createEventDispatcher` and the `on:` directive in favour of callback props and normal element properties, we:
175+
176+
- reduce Svelte's learning curve
177+
- remove boilerplate, particularly around `createEventDispatcher`
178+
- remove the overhead of creating `CustomEvent` objects for events that may not even have listeners
179+
- add the ability to spread event handlers
180+
- add the ability to know which event handlers were provided to a component
181+
- add the ability to express whether a given event handler is required or optional (props with default values are considered optional, those without are considered required)
182+
- increase type safety (previously, it was effectively impossible for Svelte to guarantee that a component didn't emit a particular event)

0 commit comments

Comments
 (0)