diff --git a/.changeset/four-beers-like.md b/.changeset/four-beers-like.md
new file mode 100644
index 0000000000..967d76af66
--- /dev/null
+++ b/.changeset/four-beers-like.md
@@ -0,0 +1,5 @@
+---
+'svelte': patch
+---
+
+fix: prevent hydration error on async `{@html ...}`
diff --git a/documentation/docs/02-runes/04-$effect.md b/documentation/docs/02-runes/04-$effect.md
index d41c5b8e6a..a13fc7bc46 100644
--- a/documentation/docs/02-runes/04-$effect.md
+++ b/documentation/docs/02-runes/04-$effect.md
@@ -41,9 +41,11 @@ You can use `$effect` anywhere, not just at the top level of a component, as lon
> [!NOTE] Svelte uses effects internally to represent logic and expressions in your template — this is how `
hello {name}!
` updates when `name` changes.
-An effect can return a _teardown function_ which will run immediately before the effect re-runs ([demo](/playground/untitled#H4sIAAAAAAAAE42SQVODMBCF_8pOxkPRKq3HCsx49K4n64xpskjGkDDJ0tph-O8uINo6HjxB3u7HvrehE07WKDbiyZEhi1osRWksRrF57gQdm6E2CKx_dd43zU3co6VB28mIf-nKO0JH_BmRRRVMQ8XWbXkAgfKtI8jhIpIkXKySu7lSG2tNRGZ1_GlYr1ZTD3ddYFmiosUigbyAbpC2lKbwWJkIB8ZhhxBQBWRSw6FCh3sM8GrYTthL-wqqku4N44TyqEgwF3lmRHr4Op0PGXoH31c5rO8mqV-eOZ49bikgtcHBL55tmhIkEMqg_cFB2TpFxjtg703we6NRL8HQFCS07oSUCZi6Rm04lz1yytIHBKoQpo1w6Gsm4gmyS8b8Y5PydeMdX8gwS2Ok4I-ov5NZtvQde95GMsccn_1wzNKfu3RZtS66cSl9lvL7qO1aIk7knbJGvefdtIOzi73M4bYvovUHDFk6AcX_0HRESxnpBOW_jfCDxIZCi_1L_wm4xGQ60wIAAA==)).
+An effect can return a _teardown function_ which will run immediately before the effect re-runs:
+
```svelte
+
+
@@ -236,6 +254,7 @@ When using [`await`](await-expressions) in components, the `$effect.pending()` r
pending promises: {$effect.pending()}
{/if}
```
+
## `$effect.root`
@@ -285,9 +304,11 @@ In general, `$effect` is best considered something of an escape hatch — useful
If you're using an effect because you want to be able to reassign the derived value (to build an optimistic UI, for example) note that [deriveds can be directly overridden]($derived#Overriding-derived-values) as of Svelte 5.25.
-You might be tempted to do something convoluted with effects to link one value to another. The following example shows two inputs for "money spent" and "money left" that are connected to each other. If you update one, the other should update accordingly. Don't use effects for this ([demo](/playground/untitled#H4sIAAAAAAAAE5WRTWrDMBCFryKGLBJoY3fRjWIHeoiu6i6UZBwEY0VE49TB-O6VxrFTSih0qe_Ne_OjHpxpEDS8O7ZMeIAnqC1hAP3RA1990hKI_Fb55v06XJA4sZ0J-IjvT47RcYyBIuzP1vO2chVHHFjxiQ2pUr3k-SZRQlbBx_LIFoEN4zJfzQph_UMQr4hRXmBd456Xy5Uqt6pPKHmkfmzyPAZL2PCnbRpg8qWYu63I7lu4gswOSRYqrPNt3CgeqqzgbNwRK1A76w76YqjFspfcQTWmK3vJHlQm1puSTVSeqdOc_r9GaeCHfUSY26TXry6Br4RSK3C6yMEGT-aqVU3YbUZ2NF6rfP2KzXgbuYzY46czdgyazy0On_FlLH3F-UDXhgIO35UGlA1rAgAA)):
+You might be tempted to do something convoluted with effects to link one value to another. The following example shows two inputs for "money spent" and "money left" that are connected to each other. If you update one, the other should update accordingly. Instead of using effects for this...
+
```svelte
+
+
+
+```
```svelte
@@ -163,6 +179,7 @@ The fallback value of a prop not declared with `$bindable` is left untouched —
clicks: {object.count}
```
+
In summary: don't mutate props. Either use callback props to communicate changes, or — if parent and child should share the same object — use the [`$bindable`]($bindable) rune.
diff --git a/documentation/docs/02-runes/07-$inspect.md b/documentation/docs/02-runes/07-$inspect.md
index f67e250b45..00857f3ef4 100644
--- a/documentation/docs/02-runes/07-$inspect.md
+++ b/documentation/docs/02-runes/07-$inspect.md
@@ -5,9 +5,11 @@ tags: rune-inspect
> [!NOTE] `$inspect` only works during development. In a production build it becomes a noop.
-The `$inspect` rune is roughly equivalent to `console.log`, with the exception that it will re-run whenever its argument changes. `$inspect` tracks reactive state deeply, meaning that updating something inside an object or array using fine-grained reactivity will cause it to re-fire ([demo](/playground/untitled#H4sIAAAAAAAACkWQ0YqDQAxFfyUMhSotdZ-tCvu431AXtGOqQ2NmmMm0LOK_r7Utfby5JzeXTOpiCIPKT5PidkSVq2_n1F7Jn3uIcEMSXHSw0evHpAjaGydVzbUQCmgbWaCETZBWMPlKj29nxBDaHj_edkAiu12JhdkYDg61JGvE_s2nR8gyuBuiJZuDJTyQ7eE-IEOzog1YD80Lb0APLfdYc5F9qnFxjiKWwbImo6_llKRQVs-2u91c_bD2OCJLkT3JZasw7KLA2XCX31qKWE6vIzNk1fKE0XbmYrBTufiI8-_8D2cUWBA_AQAA)):
+The `$inspect` rune is roughly equivalent to `console.log`, with the exception that it will re-run whenever its argument changes. `$inspect` tracks reactive state deeply, meaning that updating something inside an object or array using fine-grained reactivity will cause it to re-fire:
+
```svelte
+
@@ -71,6 +73,7 @@ Snippets can be declared anywhere inside your component. They can reference valu
{@render hello('alice')}
{@render hello('bob')}
```
+
...and they are 'visible' to everything in the same lexical scope (i.e. siblings, and children of those siblings):
@@ -91,9 +94,11 @@ Snippets can be declared anywhere inside your component. They can reference valu
{@render x()}
```
-Snippets can reference themselves and each other ([demo](/playground/untitled#H4sIAAAAAAAAE2WPTQqDMBCFrxLiRqH1Zysi7TlqF1YnENBJSGJLCYGeo5tesUeosfYH3c2bee_jjaWMd6BpfrAU6x5oTvdS0g01V-mFPkNnYNRaDKrxGxto5FKCIaeu1kYwFkauwsoUWtZYPh_3W5FMY4U2mb3egL9kIwY0rbhgiO-sDTgjSEqSTvIDs-jiOP7i_MHuFGAL6p9BtiSbOTl0GtzCuihqE87cqtyam6WRGz_vRcsZh5bmRg3gju4Fptq_kzQBAAA=)):
+Snippets can reference themselves and each other:
+
```svelte
+
{#snippet blastoff()}
🚀
{/snippet}
@@ -109,14 +114,17 @@ Snippets can reference themselves and each other ([demo](/playground/untitled#H4
{@render countdown(10)}
```
+
## Passing snippets to components
### Explicit props
-Within the template, snippets are values just like any other. As such, they can be passed to components as props ([demo](/playground/untitled#H4sIAAAAAAAAE3VS247aMBD9lZGpBGwDASRegonaPvQL2qdlH5zYEKvBNvbQLbL875VzAcKyj3PmzJnLGU8UOwqSkd8KJdaCk4TsZS0cyV49wYuJuQiQpGd-N2bu_ooaI1YwJ57hpVYoFDqSEepKKw3mO7VDeTTaIvxiRS1gb_URxvO0ibrS8WanIrHUyiHs7Vmigy28RmyHHmKvDMbMmFq4cQInvGSwTsBYWYoMVhCSB2rBFFPsyl0uruTlR3JZCWvlTXl1Yy_mawiR_rbZKZrellJ-5JQ0RiBUgnFhJ9OGR7HKmwVoilXeIye8DOJGfYCgRlZ3iE876TBsZPX7hPdteO75PC4QaIo8vwNPePmANQ2fMeEFHrLD7rR1jTNkW986E8C3KwfwVr8HSHOSEBT_kGRozyIkn_zQveXDL3rIfPJHtUDwzShJd_Qk3gQCbOGLsdq4yfTRJopRuin3I7nv6kL7ARRjmLdBDG3uv1mhuLA3V2mKtqNEf_oCn8p9aN-WYqH5peP4kWBl1UwJzAEPT9U7K--0fRrrWnPTXpCm1_EVdXjpNmlA8G1hPPyM1fKgMqjFHjctXGjLhZ05w0qpDhksGrybuNEHtJnCalZWsuaTlfq6nPaaBSv_HKw-K57BjzOiVj9ZKQYKzQjZodYFqydYTRN4gPhVzTDO2xnma3HsVWjaLjT8nbfwHy7Q5f2dBAAA)):
+Within the template, snippets are values just like any other. As such, they can be passed to components as props:
+
```svelte
+
+
+
+ {#if header}
+
+
{@render header()}
+
+ {/if}
+
+
+ {#each data as d}
+
{@render row(d)}
+ {/each}
+
+
+
+
```
+
Think about it like passing content instead of data to a component. The concept is similar to slots in web components.
### Implicit props
-As an authoring convenience, snippets declared directly _inside_ a component implicitly become props _on_ the component ([demo](/playground/untitled#H4sIAAAAAAAAE3VSTa_aMBD8Kyu_SkAbCA-JSzBR20N_QXt6vIMTO8SqsY29tI2s_PcqTiB8vaPHs7MzuxuIZgdBMvJLo0QlOElIJZXwJHsLBBvb_XUASc7Mb9Yu_B-hsMMK5sUzvDQahUZPMkJ96aTFfKd3KA_WOISfrFACKmcOMFmk8TWUTjY73RFLoz1C5U4SPWzhrcN2GKDrlcGEWauEnyRwxCaDdQLWyVJksII2uaMWTDPNLtzX5YX8-kgua-GcHJVXI3u5WEPb0d83O03TMZSmfRzOkG1Db7mNacOL19JagVALxoWbztq-H8U6j0SaYp2P2BGbOyQ2v8PQIFMXLKRDk177pq0zf6d8bMrzwBdd0pamyPMb-IjNEzS2f86Gz_Dwf-2F9nvNSUJQ_EOSoTuJNvngqK5v4Pas7n4-OCwlEEJcQTIMO-nSQwtb-GSdsX46e9gbRoP9yGQ11I0rEuycunu6PHx1QnPhxm3SFN15MOlYEFJZtf0dUywMbwZOeBGsrKNLYB54-1R9WNqVdki7usim6VmQphf7mnpshiQRhNAXdoOfMyX3OgMlKtz0cGEcF27uLSul3mewjPjgOOoDukxjPS9rqfh0pb-8zs6aBSt_7505aZ7B9xOi0T9YKW4UooVsr0zB1BTrWQJ3EL-oWcZ572GxFoezCk37QLe3897-B2i2U62uBAAA)):
+As an authoring convenience, snippets declared directly _inside_ a component implicitly become props _on_ the component:
+
```svelte
-
+
+
+
{#snippet header()}
fruit
@@ -169,12 +225,54 @@ As an authoring convenience, snippets declared directly _inside_ a component imp
```
+```svelte
+
+
+
+
+ {#if header}
+
+
{@render header()}
+
+ {/if}
+
+
+ {#each data as d}
+
{@render row(d)}
+ {/each}
+
+
+
+
+```
+
+
### Implicit `children` snippet
-Any content inside the component tags that is _not_ a snippet declaration implicitly becomes part of the `children` snippet ([demo](/playground/untitled#H4sIAAAAAAAAE3WOQQrCMBBFrzIMggql3ddY1Du4si5sOmIwnYRkFKX07lKqglqX8_7_w2uRDw1hjlsWI5ZqTPBoLEXMdy3K3fdZDzB5Ndfep_FKVnpWHSKNce1YiCVijirqYLwUJQOYxrsgsLmIOIZjcA1M02w4n-PpomSVvTclqyEutDX6DA2pZ7_ABIVugrmEC3XJH92P55_G39GodCmWBFrQJ2PrQAwdLGHig_NxNv9xrQa1dhWIawrv1Wzeqawa8953D-8QOmaEAQAA)):
+Any content inside the component tags that is _not_ a snippet declaration implicitly becomes part of the `children` snippet:
+
```svelte
+
+
```
@@ -187,6 +285,7 @@ Any content inside the component tags that is _not_ a snippet declaration implic
```
+
> [!NOTE] Note that you cannot have a prop called `children` if you also have content inside the component — for this reason, you should avoid having props with that name
@@ -256,9 +355,21 @@ We can tighten things up further by declaring a generic, so that `data` and `row
## Exporting snippets
-Snippets declared at the top level of a `.svelte` file can be exported from a `
+
+{@render add(1, 2)}
+
+```
```svelte
+
@@ -267,6 +378,7 @@ Snippets declared at the top level of a `.svelte` file can be exported from a `<
{a} + {b} = {a + b}
{/snippet}
```
+
> [!NOTE]
> This requires Svelte 5.5.0 or newer
diff --git a/documentation/docs/03-template-syntax/12-bind.md b/documentation/docs/03-template-syntax/12-bind.md
index be84969b87..e8164149db 100644
--- a/documentation/docs/03-template-syntax/12-bind.md
+++ b/documentation/docs/03-template-syntax/12-bind.md
@@ -54,9 +54,11 @@ A `bind:value` directive on an `` element binds the input's `value` prope
{message}
```
-In the case of a numeric input (`type="number"` or `type="range"`), the value will be coerced to a number ([demo](/playground/untitled#H4sIAAAAAAAAE6WPwYoCMQxAfyWEPeyiOOqx2w74Hds9pBql0IllmhGXYf5dKqwiyILsLXnwwsuI-5i4oPkaUX8yo7kCnKNQV7dNzoty4qSVBSr8jG-Poixa0KAt2z5mbb14TaxA4OCtKCm_rz4-f2m403WltrlrYhMFTtcLNkoeFGqZ8yhDF7j3CCHKzpwoDexGmqCL4jwuPUJHZ-dxVcfmyYGe5MAv-La5pbxYFf5Z9Zf_UJXb-sEMquFgJJhBmGyTW5yj8lnRaD_w9D1dAKSSj7zqAQAA)):
+In the case of a numeric input (`type="number"` or `type="range"`), the value will be coerced to a number:
+
```svelte
+
+
Customize your burrito
+
@@ -165,7 +171,17 @@ Inputs that work together can use `bind:group` ([demo](/playground/untitled#H4sI
+
+
Tortilla: {tortilla}
+
Fillings: {fillings.join(', ') || 'None'}
+
+
```
+
> [!NOTE] `bind:group` only works if the inputs are in the same Svelte component.
diff --git a/documentation/docs/03-template-syntax/19-await-expressions.md b/documentation/docs/03-template-syntax/19-await-expressions.md
index aa3f907b14..04437f5ee3 100644
--- a/documentation/docs/03-template-syntax/19-await-expressions.md
+++ b/documentation/docs/03-template-syntax/19-await-expressions.md
@@ -25,9 +25,11 @@ The experimental flag will be removed in Svelte 6.
## Synchronized updates
-When an `await` expression depends on a particular piece of state, changes to that state will not be reflected in the UI until the asynchronous work has completed, so that the UI is not left in an inconsistent state. In other words, in an example like [this](/playground/untitled#H4sIAAAAAAAAE42QsWrDQBBEf2VZUkhYRE4gjSwJ0qVMkS6XYk9awcFpJe5Wdoy4fw-ycdykSPt2dpiZFYVGxgrf2PsJTlPwPWTcO-U-xwIH5zli9bminudNtwEsbl-v8_wYj-x1Y5Yi_8W7SZRFI1ZYxy64WVsjRj0rEDTwEJWUs6f8cKP2Tp8vVIxSPEsHwyKdukmA-j6jAmwO63Y1SidyCsIneA_T6CJn2ZBD00Jk_XAjT4tmQwEv-32eH6AsgYK6wXWOPPTs6Xy1CaxLECDYgb3kSUbq8p5aaifzorCt0RiUZbQcDIJ10ldH8gs3K6X2Xzqbro5zu1KCHaw2QQPrtclvwVSXc2sEC1T-Vqw0LJy-ClRy_uSkx2ogHzn9ADZ1CubKAQAA)...
+When an `await` expression depends on a particular piece of state, changes to that state will not be reflected in the UI until the asynchronous work has completed, so that the UI is not left in an inconsistent state. In other words, in an example like this...
+
```svelte
+
+
+
+
{@html await firstTest()}
+ {await otherTest()}
+
diff --git a/packages/svelte/tests/runtime-runes/samples/async-overlap-multiple-fork-3/_config.js b/packages/svelte/tests/runtime-runes/samples/async-overlap-multiple-fork-3/_config.js
new file mode 100644
index 0000000000..61360d8dc9
--- /dev/null
+++ b/packages/svelte/tests/runtime-runes/samples/async-overlap-multiple-fork-3/_config.js
@@ -0,0 +1,43 @@
+import { tick } from 'svelte';
+import { test } from '../../test';
+
+export default test({
+ skip: true,
+ async test({ assert, target }) {
+ await tick();
+ const [a_b_fork, a_c, b_d, shift, pop, commit] = target.querySelectorAll('button');
+ const [p] = target.querySelectorAll('p');
+
+ a_b_fork.click();
+ await tick();
+ assert.htmlEqual(p.innerHTML, 'a 0 | b 0 | c 0 | d 0');
+
+ a_c.click();
+ await tick();
+ assert.htmlEqual(p.innerHTML, 'a 0 | b 0 | c 0 | d 0');
+
+ b_d.click();
+ await tick();
+ assert.htmlEqual(p.innerHTML, 'a 0 | b 0 | c 0 | d 0');
+
+ shift.click();
+ await tick();
+ assert.htmlEqual(p.innerHTML, 'a 0 | b 0 | c 0 | d 0');
+
+ shift.click();
+ await tick();
+ assert.htmlEqual(p.innerHTML, 'a 0 | b 0 | c 0 | d 0');
+
+ shift.click();
+ await tick();
+ assert.htmlEqual(p.innerHTML, 'a 1 | b 0 | c 1 | d 0');
+
+ shift.click();
+ await tick();
+ assert.htmlEqual(p.innerHTML, 'a 1 | b 1 | c 1 | d 1');
+
+ commit.click();
+ await tick();
+ assert.htmlEqual(p.innerHTML, 'a 1 | b 1 | c 1 | d 1');
+ }
+});
diff --git a/packages/svelte/tests/runtime-runes/samples/async-overlap-multiple-fork-3/main.svelte b/packages/svelte/tests/runtime-runes/samples/async-overlap-multiple-fork-3/main.svelte
new file mode 100644
index 0000000000..6d1c4ab418
--- /dev/null
+++ b/packages/svelte/tests/runtime-runes/samples/async-overlap-multiple-fork-3/main.svelte
@@ -0,0 +1,31 @@
+
+
+
a {await delay(a)} | b {await delay(b)} | c {c} | d {d}