Skip to content

Commit fc83498

Browse files
docs: replace event handlers with event props on preview site (#9793)
also add event and snippets section to old vs new --------- Co-authored-by: Rich Harris <[email protected]> Co-authored-by: Simon H <[email protected]>
1 parent 4b76c69 commit fc83498

File tree

3 files changed

+120
-17
lines changed

3 files changed

+120
-17
lines changed

sites/svelte-5-preview/src/routes/defaults.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ export const default_files = [
1111
}
1212
</script>
1313
14-
<button on:click={increment}>
14+
<button onclick={increment}>
1515
clicks: {count}
1616
</button>
1717
`

sites/svelte-5-preview/src/routes/docs/content/02-examples/01-universal-reactivity.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ Suppose we have a component like this:
1515
}
1616
</script>
1717
18-
<button on:click={increment}>
18+
<button onclick={increment}>
1919
clicks: {count}
2020
</button>
2121
```
@@ -40,9 +40,9 @@ We can encapsulate this logic in a function, so that it can be used in multiple
4040
+ const counter = createCounter();
4141
</script>
4242

43-
-<button on:click={increment}>
43+
-<button onclick={increment}>
4444
- clicks: {count}
45-
+<button on:click={counter.increment}>
45+
+<button onclick={counter.increment}>
4646
+ clicks: {counter.count}
4747
</button>
4848
```
@@ -78,12 +78,12 @@ export function createCounter() {
7878
const counter = createCounter();
7979
</script>
8080

81-
<button on:click={counter.increment}>
81+
<button onclick={counter.increment}>
8282
clicks: {counter.count}
8383
</button>
8484
```
8585

86-
[See this example in the playground.](/#H4sIAAAAAAAACmVQ0U7DMAz8FStC2iaqDl67dhLiMxgPI3NRRutUiYNAVf6dJG1TBk-W7bvznUfRqg6tqF5GQeceRSWehkEUgr-H2NhP7BhDb7UzMk5qK40a-HiiE6t-0IZhBGnwzPisHTEa8NAa3cOm3MtpUk4y5dVuDoEXmFKTZZjX0NwKbHcBVe_XQ1S_OWZNoKmSnZIfzbgoKwrUHol9cpS2toK8T9VHuUniGLL0-qJahRdRsXHoixz91u76hav9_QH8SqlbR5JVMPXHO4zRSIdzvBDuznIAbB92c_jMzOYXVnxM5Nw38BjB0XksBtkZWjDvi_ZKy5A0P0xDX0w1n0mKYen_P-HV_wBwv1jcCwIAAA==)
86+
[See this example in the playground.](/#H4sIAAAAAAAAE2VQ0U7DMAz8FStC2iaqDl67dhLiMxgPI3NRRutUiYNAVf6dJG1TBk-W7bvznUfRqg6tqF5GQeceRSWehkEUgr-H2NhP7BhDb7UzMk5qK40a-HiiE6t-0IZhBGnwzPisHTEa8NAa3cOm3MtpUk4y5dVuDoEXmFKTZZjX0NwKbHcBVe_XQ1S_OWZNoEl2Sn404yKsKDB7JPbJUNraCvI-VR_VJoVjiNLri2oVXkTFxqEvcvJbt-sTrvb3A_ArhW4dSVbB0x_rMEYjHc7pQrY7ywGwfdjN2TMzm19Y8S-Rc9_AYwRH57EYZGdowbwv2istQ9L8MA19MdV8JimGpf__hFf_Ay1mGDQKAgAA)
8787

8888
## Stores equivalent
8989

@@ -115,7 +115,7 @@ Back in the component, we retrieve the store value by prefixing its name with `$
115115
const counter = createCounter();
116116
</script>
117117

118-
<button on:click={counter.increment}>
118+
<button onclick={counter.increment}>
119119
- clicks: {counter.count}
120120
+ clicks: {$counter}
121121
</button>

sites/svelte-5-preview/src/routes/docs/content/02-examples/04-old-vs-new.md

Lines changed: 113 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@
22
title: Old vs new
33
---
44

5-
This page intends to give a broad overview of how code written using runes looks compared to code not using them. You will see that for most simple tasks that only involve a single component it will actually not look much different. For more complex logic, runes simplify things.
5+
This page intends to give a broad overview of how code written using the new APIs looks compared to code not using them. You will see that for most simple tasks that only involve a single component it will actually not look much different. For more complex logic, they simplify things.
66

77
## Counter
88

9-
The `$state`, `$derived` and `$effect` runes replace magic `let` declarations, `$: x = ...` and `$: { ... }`.
9+
The `$state`, `$derived` and `$effect` runes replace magic `let` declarations, `$: x = ...` and `$: { ... }`. Event handlers can be written as event attributes now, which in practise means just removing the colon.
1010

1111
- [Before](/#H4sIAAAAAAAAE0VP0Q6CMAz8lbqYAGqC-jiBxH_wTXzQUWRxbgQ6E7Ps34VN40vbu8u1V8daqXBk_OyYvj6RcXbse7Zh9O5nML5QEU54NHYQM1OMYpA9VbWuSSGBMFYTlLA9zMySQ2PsTeHERGUF-6B8VRdmki2kUa9gt81-dE1XhQOlyckY6OS9WyRZdJOf21SK_B9AFzdLZDQYzYWS4lG6NIOyiqfXax9SuoA85OBitrAlOqvptadpZCuxYZwGi_7iP__ps0sVAQAA)
1212
- [After](/#H4sIAAAAAAAAE0VPzW7CMAx-FRMhkQ4k2I6lrbR32I3uUBJnRAtJlThIKMq7jzSgHSzr-_FnOzGlDQbWnhKz0xVZyz7nme0Y3ecCwg0N4QMHF70oTBeE1zMNox3JIIFw0RL0sA40EfJDc3wp0sWzwSJJ9PqGklfvG3xUU6k1KoWCOG-gHyAtNGkFT-8A74fmRY80GfTEN1_OwUX_XFabZxDl0nJB3f7_QNudI5Gz4GwrjBa_fap7lvDtNi9fpAVl2EOqJ-eSUieHx-tXJ7XSKFlLPmL-zn8TVUg5NQEAAA==)
@@ -27,7 +27,8 @@ The `$state`, `$derived` and `$effect` runes replace magic `let` declarations, `
2727
+ });
2828
</script>
2929

30-
<button on:click={() => count++}>
30+
-<button on:click={() => count++}>
31+
+<button onclick={() => count++}>
3132
{count} / {double}
3233
</button>
3334
```
@@ -56,8 +57,10 @@ In runes mode, dependencies are tracked at _run time_. `sum` will be recalculate
5657
}
5758
</script>
5859

59-
<button on:click={() => a++}>a++</button>
60-
<button on:click={() => b++}>b++</button>
60+
-<button on:click={() => a++}>a++</button>
61+
-<button on:click={() => b++}>b++</button>
62+
+<button onclick={() => a++}>a++</button>
63+
+<button onclick={() => b++}>b++</button>
6164
<p>{a} + {b} = {sum}</p>
6265
```
6366

@@ -88,8 +91,10 @@ In non-runes mode, we 'hide' the dependency from the compiler by excluding it fr
8891
}
8992
</script>
9093

91-
<button on:click={() => a++}>a++</button>
92-
<button on:click={() => b++}>b++</button>
94+
-<button on:click={() => a++}>a++</button>
95+
-<button on:click={() => b++}>b++</button>
96+
+<button onclick={() => a++}>a++</button>
97+
+<button onclick={() => b++}>b++</button>
9398
<p>{a} + {b} = {sum}</p>
9499
```
95100

@@ -130,7 +135,7 @@ With runes, we can use `$effect.pre`, which behaves the same as `$effect` but ru
130135
`beforeUpdate`, and its equally troublesome counterpart `afterUpdate`, will be deprecated in Svelte 5.
131136

132137
- [Before](/#H4sIAAAAAAAAE31WXa_bNgz9K6yL1QmWOLlrC-w6H8MeBgwY9tY9NfdBtmlbiywZkpyPBfnvo2zLcZK28AWuRPGI5OGhkEuQc4EmiL9eAskqDOLg97oOZoE9125jDigs0t6oRqfOsjap5rXd7uTO8qpW2sIFEsyVxn_qjFmcAcstar-xPN3DFXKtKgi768IVgQku0ELj3Lgs_kZjWIEGNpAzYXDlHWyJFZI1zJjeh4O5uvl_DY8oUkVeVoFuJKYls-_CGYS25Aboj0EtWNqel0wWoBoLTGZgmdgDS9zW4Uz4NsrswPHoyutN4xInkylstnBxdmIhh8m7xzqmoNE2Wq46n1RJQzEbq4g-JQSl7e-HDx-GdaTy3KD9E3lRWvj5Zu9QX1QN20dj7zyHz8s-1S6lW7Cpz3RnXTcm04hIlfdFuO8p2mQ5-3a06cqjrn559bF_2NHOnRZ5I1PLlXQNyQT-hedMHeUEDyjtdMxsa4n2eIbNhlTwhyRthaOKOmYtniwF6pwt0wXa6MBEg0OibZec27gz_dk3UrZ6hB2LLYoiv521Yd8Gt-foTrfhiCDP0lC9VUUhcDLU49Xe_9943cNvEArHfAjxeBTovvXiNpFynfEDpIIZs9kFbg52QbeNHWZzebz32s7xHco3nJAJl1nshmhz8dYOQJDyZetnbb2gTWe-vEeWlrfpZMavr56ldb29eNt6UXvgwgFbp_WC0tl2RK25rGk6lYz3nUI2lzvBXGHhPZPGWmKUXFNBKqdaW259wl_aHbiqoVIZdpE60Nax6IOujT0LbFFxIVTCxCRR2XloUcYNvSbnGHKBp763jHoj59xiZWJI0Wm0P_m3MSS985xkasn-cFq20xTDy3J5KFcjgUTD69BHdcHIjz431z28IqlxGcPSfdFnrGDZn6gD6lyo45zyHAD-btczf-98nhQxHEvKfeUtOVkSejD3q-9X7JbzjGtsdUxlKdFU8qGsT78uaw848syWMXz85Waq2Gnem4mAn3prweq4q6Y3JEpnqMmnPoFRgmd3ySW0LLRqSKlwYHriCvJvUs2yjMaaoA-XzTXLeGMe45zmhv_XAno3Mj0xF7USuqNvnE9H343QHlq-eAgxpbTPNR9yzUkgLjwSR0NK4wKoxy-jDg-9vy8sUSToakzW-9fX13Em9Q8T6Z26uZhBN36XUYo5q7ggLXBZoub2Ofv7g6GCZfTxe034NCjiudXj7Omla0eTfo7QBPOcYxbE7qG-vl3_B1G-_i_JCAAA)
133-
- [After](/#H4sIAAAAAAAAE31WXa-jNhD9K7PsdknUQJLurtRLPqo-VKrU1327uQ8GBnBjbGSb5KZR_nvHgMlXtyIS9njO-MyZGZRzUHCBJkhez4FkNQZJ8HvTBLPAnhq3MQcUFmlvVKszZ1mbTPPGbndyZ3ndKG3hDJZne7hAoVUNYY8JV-RBPgIt2AprhA18MpZZnIQ50_twuvLHNRrDSjRXj9fwiCJTBLIKdCsxq5j9EM4gtBU3QD8GjWBZd14xWYJqLTCZg2ViDyx1W4cz4dv0hsiB49FRHkyfsCgws3GjcTKZwmYLZ2feWc9o1W8zJQ2Fb62i5JUQRNRHgs-fx3WsisKg_RN5WVn4-WrvUd9VA9tH4-AcwbfFQIpkLWByvWzqSe2sk3kyjUlOec_XPU-3TRaz_75tuvKoi19e3OvipSpamVmupJM2F_gXnnJ1lBM8oLQjHceys8R7PMFms4HwD2lRhzeEe-EsvluSrHe2TJdo4wMTLY48XKwPzm0KGm2r5ajFtRYU4TWOY7-ddWHfxhDP0QkQhnf5PWRnVVkKnIx8fZsOb5dR16nwG4TCCRdCMphWQ7z1_DoOcp3zA2SCGbPZBa5jd0G_TRxmc36Me-mG6A7l60XIlMs8ce2-OXtrDyBItdz6qVjPadObzx-RZdV1nJjx64tXad1sz962njceOHfAzmk9JzrbXqg1lw3NkZLJvu-AzfmuIS4w955pay0pSq6ZoCalXDttPeHv3Q5c1lCrHPubetDWqegvXRt7EtihklKolIlJqvLTWKKcG5r7UwKFwPehtoxqIyNusTYJZOh6cDj5uzXUWqeI2tCS_eG06oYhgeVicahWNw0Sj8M93OouIz963FgO8JpajcsEFu6Jv2ENi-FEHVAXQh0j4jkCfGxXMx83itIygWNF3FfeUpAlpU_bfvXjjN0yyrnGro8pLSXaWj6k9fXXReMBR57bKoEvv1xNNXuPBjMJ8NNgLVmT9NkMhlTpHDX5NO9glOD5HbmUlqVWLXUqHJieuIT8J6Vhec4lZbN8CBZplvPWPN7zHhn-TwcY3Mj0pFzctdCdfLd8evmugg7QaukhpJTSnmsxci2oQdz1SBqNlG4ToBovbyo81v4-sVRRQ9e3Yn18eXm5ZdL8L5HBqZ-LGfTjd76hWLCaC-oFLivU3D6zvz8YM1jEX35UhK9jRzyX-pY9fem60aT_AjTBvOCYB4nVLV7eLv8CKAV_uEYIAAA=)
138+
- [After](/#H4sIAAAAAAAAE31WXa-jNhD9K7PsdknUQJLurtRLPqo-VKrU1327uQ8GBnBjbGSb5KZR_nvHgMlXtyIS9njO-MyZGZRzUHCBJkhez4FkNQZJ8HvTBLPAnhq3MQcUFmlvVKszZ1mbTPPGbndyZ3ndKG3hDJZne7hAoVUNYY8JV-RBPgIt2AprhA18MpZZnIQ50_twuvLHNRrDSjRXj9fwiCJTBLIKdCsxq5j9EM4gtBU3QD8GjWBZd14xWYJqLTCZg2ViDyx1W4cz4dv0hsiB49FRHkyfsCgws3GjcTKZwmYLZ2feWc9o1W8zJQ2Fb62i5JUQRNRHgs-fx3WsisKg_RN5WVn4-WrvUd9VA9tH4-AcwbfFQIpkLWByvWzqSe2sk3kyjUlOec_XPU-3TRaz_75tuvKoi19e3OvipSpamVmupJM2F_gXnnJ1lBM8oLQjHceys8R7PMFms4HwD2lRhzeEe-EsvluSrHe2TJdo4wMTLY48XKwPzm0KGm2r5ajFtRYU4TWOY7-ddWHfxhDP0QkQhnf5PWRnVVkKnIx8fZsOb5dR16nwG4TCCRdCMphWQ7z1_DoOcp3zA2SCGbPZBa5jd0G_TRxmc36Me-mG6A7l60XIlMs8ce2-OXtrDyBItdz6qVjPadObzx-RZdV1nJjx64tXad1sz962njceOHfAzmk9JzrbXqg1lw3NkZL7vgE257t-uMDcO6attSSokpmgFqVMO2U93e_dDlzOUKsc-3t6zNZp6K9cG3sS2KGSUqiUiUmq8tNYoJwbmvpTAoXA96GyjCojI26xNglk6DpwOPm7NdRYp4ia0JL94bTqRiGB5WJxqFY37RGPoz3c6i4jP3rcUA7wmhqNywQW7om_YQ2L4UQdUBdCHSPiOQJ8bFcxHzeK0jKBY0XcV95SkCWlD9t-9eOM3TLKucauiyktJdpaPqT19ddF4wFHntsqgS-_XE01e48GMwnw02AtWZP02QyGVOkcNfk072CU4PkduZSWpVYt9SkcmJ64hPwHpWF5ziVls3wIFmmW89Y83vMeGf5PBxjcyPSkXNy10J18t3x6-a6CDtBq6SGklNKeazFyLahB3PVIGo2UbhOgGi9vKjzW_j6xVFFD17difXx5ebll0vwvkcGpn4sZ9MN3vqFYsJoL6gUuK9TcPrO_PxgzWMRfflSEr2NHPJf6lj1957rRpH8CNMG84JgHidUtXt4u_wK21LXERAgAAA==)
134139

135140
```diff
136141
<script>
@@ -183,10 +188,108 @@ With runes, we can use `$effect.pre`, which behaves the same as `$effect` but ru
183188
{/each}
184189
</div>
185190

186-
<input on:keydown={handleKeydown} />
191+
- <input on:keydown={handleKeydown} />
192+
+ <input onkeydown={handleKeydown} />
187193

188-
<button on:click={toggle}>
194+
- <button on:click={toggle}>
195+
+ <button onclick={toggle}>
189196
Toggle dark mode
190197
</button>
191198
</div>
192199
```
200+
201+
## Forwarding events
202+
203+
Because [event handlers](event-handlers) are just regular attributes now, the "forwarding events" concept is replaced with just passing callback props. Before, you would have to mark every event that you want to forward separately. You can still do this with event attributes...
204+
205+
```diff
206+
<script>
207+
+ let { onclick, onkeydown, ...attributes } = $props();
208+
</script>
209+
210+
<button
211+
- {...$$props}
212+
+ {...attributes}
213+
- on:click
214+
- on:keydown
215+
+ {onclick}
216+
+ {onkeydown}
217+
>a button</button>
218+
```
219+
220+
...but in practise what you probably _really_ want to do in these situations is forward _all_ events. This wasn't possible before, but it is now:
221+
222+
```diff
223+
<script>
224+
+ let { ...props } = $props();
225+
</script>
226+
227+
<button
228+
- {...$$props}
229+
- on:click
230+
- on:keydown
231+
+ {...props}
232+
>a button</button>
233+
```
234+
235+
- [Before](https://svelte-5-preview.vercel.app/#H4sIAAAAAAAACn1Py2rDMBD8lWUJOIEg3xXb0P5G1YMjr4morBXSuhCM_z1xlLaXktMys8xrwdF5yqg_Fgz9RKjxLUY8olzjBvI3eaE7zjwnuzFNtslF6Uww4qbISeB9FuEAY-IJKlUXqIq0OpnQ1H-a0JT3Js9y9dQatOw5aUg0GNx4Dtp6Z7_aZX-AtoPeU5J99eBoALkQnB8m1WE1oe7u9SYe3OhoQC1ppvX4u6akvRxUvGBRSu12MXHMK_xU6PpnVFOX-0_Y53oDgvtVGEYBAAA=)
236+
- [After](https://svelte-5-preview.vercel.app/#H4sIAAAAAAAACo1PQWrEMAz8ihCFJLA492wSaL9R95A6CjV1bGMrhcX4793Eu9tDe-hJmpFGmkm4aEMRu9eEdloJO3z2Hk_IF7-D-EWG6Yqj24LamT6qoD2P0krWq3eB4WVjdhaW4FaoRFugKNLqLG3f_mhsX8a7PPLF0CBROeNCB4FmiTvvrDJafQ6pbmAYYTIUuK4OjmbgD4L340bVZGnb8epudbNeNM3Ycdgonx5hyrP_5jHEkEAI4YPzETIM8HS0dfMrRrEA6b6dx-lmq29L_cPYW_4GVdmFa3EBAAA=)
237+
238+
## Passing UI content to a component
239+
240+
Previously, you would pass UI content into components using slots. Svelte 5 provides a better mechanism for this, [snippets](snippets). In the simple case of passing something to the default slot, nothing has changed for the consumer:
241+
242+
```svelte
243+
<!-- same with both slots and snippets -->
244+
<script>
245+
import Button from './Button.svelte';
246+
</script>
247+
248+
<Button>click me</Button>
249+
```
250+
251+
Inside `Button.svelte`, use `@render` instead of the `<slot>` tag. The default content is passed as the `children` prop:
252+
253+
```diff
254+
<script>
255+
+ let { children } = $props();
256+
</script>
257+
258+
<button>
259+
- <slot />
260+
+ {@render children()}
261+
</button>
262+
```
263+
264+
When passing props back up to the consumer, snippets make things easier to reason about, removing the need to deal with the confusing semantics of the `let:`-directive:
265+
266+
```diff
267+
<!-- provider -->
268+
<script>
269+
+ let { children } = $props();
270+
</script>
271+
272+
<button>
273+
- <slot prop="some value" />
274+
+ {@render children("some value")}
275+
</button>
276+
```
277+
278+
```diff
279+
<!-- consumer -->
280+
<script>
281+
import Button from './Button.svelte';
282+
</script>
283+
284+
- <Button let:prop>click {prop}</Button>
285+
+ <Button>
286+
+ {#snippet children(prop)}
287+
+ click {prop}
288+
+ {/snippet}
289+
+ </Button>
290+
```
291+
292+
Combined with event attributes, this reduces the number of concepts to learn — everything related to the component boundary can now be expressed through props.
293+
294+
- [Before](https://svelte-5-preview.vercel.app/#H4sIAAAAAAAACn2PzYrCQBCEX6XpSxTE3GeTgPoYzh5i0sHB-WOmIywh776ZjCgieOsqqvrrnnBQmiKK84S2NYQCD97jDvnPJxHvpJkWHd0YuuRUsQvKcyOtZGW8CwzHkdlZGIIzUOzLLPe5WvxIW5Wvjq0eaWdFp1V3q6fNFuoGWk2BN8UpedQDXwkua7LYzqCJhQ_Or1TJaxGm5MxpfV7ZLGca16tBUY-Cw0jz7vlVjnx97PJ-2MqqonYMCVTLJWoI7q0eSSKUTSLnzjJ-sn_nfxmfF-FdAQAA)
295+
- [After](https://svelte-5-preview.vercel.app/#H4sIAAAAAAAACo2PzW6DMBCEX2XlVgIkBHcKUdo-RumBwqJYNbZlL5Eqy-9e_9DkkEtv3vHMzn6OrVygZd2HY3LakHXsVWtWM_rRcbBXFIRhtmo3c1R6Oxuu6TTKkfimlSF424mUhNWoDYqmzWOTo8XLKPv2npH94VZyFnz-HlxZwXCCSaChsniPGi5AF4SvZCwqn7rck5VcaySYL1wsBmWpjdKVj58jpWXgopQU1x52H_tz5ylwbGrhK8eFdWR29PUNO1v-Sy7CHe52SQ1N08RqCx4GeE7PsnpAz0Tg_twH2TmsWNDcwcZQuiFcJ7HjyKqEkLMh8Ajx6X8BPkQdmscBAAA=)

0 commit comments

Comments
 (0)