let todos = [{ done: false, text: 'add more todos' }];
// ---cut---
todos[0].done = !todos[0].done;
```
@ -64,6 +59,17 @@ todos.push({
> [!NOTE] When you update properties of proxies, the original object is _not_ mutated.
Note that if you destructure a reactive value, the references are not reactive — as in normal JavaScript, they are evaluated at the point of destructuring:
```js
let todos = [{ done: false, text: 'add more todos' }];
// ---cut---
let { done, text } = todos[0];
// this will not affect the value of `done`
todos[0].done = !todos[0].done;
```
### Classes
You can also use `$state` in class fields (whether public or private):
@ -85,7 +91,42 @@ class Todo {
}
```
> [!NOTE] The compiler transforms `done` and `text` into `get`/`set` methods on the class prototype referencing private fields.
> [!NOTE] The compiler transforms `done` and `text` into `get`/`set` methods on the class prototype referencing private fields. This means the properties are not enumerable.
When calling methods in JavaScript, the value of [`this`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this) matters. This won't work, because `this` inside the `reset` method will be the `<button>` rather than the `Todo`:
```svelte
<buttononclick={todo.reset}>
reset
</button>
```
You can either use an inline function...
```svelte
<buttononclick=+++{()=> todo.reset()}>+++
reset
</button>
```
...or use an arrow function in the class definition:
```js
// @errors: 7006 2554
class Todo {
done = $state(false);
text = $state();
constructor(text) {
this.text = text;
}
+++reset = () => {+++
this.text = '';
this.done = false;
}
}
```
## `$state.raw`
@ -127,3 +168,90 @@ To take a static snapshot of a deeply reactive `$state` proxy, use `$state.snaps
```
This is handy when you want to pass some state to an external library or API that doesn't expect a proxy, such as `structuredClone`.
## Passing state into functions
JavaScript is a _pass-by-value_ language — when you call a function, the arguments are the _values_ rather than the _variables_. In other words:
```js
/// file: index.js
// @filename: index.js
// ---cut---
/**
* @param {number} a
* @param {number} b
*/
function add(a, b) {
return a + b;
}
let a = 1;
let b = 2;
let total = add(a, b);
console.log(total); // 3
a = 3;
b = 4;
console.log(total); // still 3!
```
If `add` wanted to have access to the _current_ values of `a` and `b`, and to return the current `total` value, you would need to use functions instead:
```js
/// file: index.js
// @filename: index.js
// ---cut---
/**
* @param {() => number} getA
* @param {() => number} getB
*/
function add(+++getA, getB+++) {
return +++() => getA() + getB()+++;
}
let a = 1;
let b = 2;
let total = add+++(() => a, () => b)+++;
console.log(+++total()+++); // 3
a = 3;
b = 4;
console.log(+++total()+++); // 7
```
State in Svelte is no different — when you reference something declared with the `$state` rune...
```js
let a = +++$state(1)+++;
let b = +++$state(2)+++;
```
...you're accessing its _current value_.
Note that 'functions' is broad —it encompasses properties of proxies and [`get`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get)/[`set`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/set) properties...
```js
/// file: index.js
// @filename: index.js
// ---cut---
/**
* @param {{ a: number, b: number }} input
*/
function add(input) {
return {
get value() {
return input.a + input.b;
}
};
}
let input = $state({ a: 1, b: 2 });
let total = add(input);
console.log(total.value); // 3
input.a = 3;
input.b = 4;
console.log(total.value); // 7
```
...though if you find yourself writing code like that, consider using [classes](#Classes) instead.
@ -74,6 +74,30 @@ You can freely use destructuring and rest patterns in each blocks.
{/each}
```
## Each blocks without an item
```svelte
<!--- copy: false --->
{#each expression}...{/each}
```
```svelte
<!--- copy: false --->
{#each expression, index}...{/each}
```
In case you just want to render something `n` times, you can omit the `as` part ([demo](/playground/untitled#H4sIAAAAAAAAE3WR0W7CMAxFf8XKNAk0WsSeUEaRpn3Guoc0MbQiJFHiMlDVf18SOrZJ48259_jaVgZmxBEZZ28thgCNFV6xBdt1GgPj7wOji0t2EqI-wa_OleGEmpLWiID_6dIaQkMxhm1UdwKpRQhVzWSaVORJNdvWpqbhAYVsYQCNZk8thzWMC_DCHMZk3wPSThNQ088I3mghD9UwSwHwlLE5PMIzVFUFq3G7WUZ2OyUvU3JOuZU332wCXTRmtPy1NgzXZtUFp8WFw9536uWqpbIgPEaDsJBW90cTOHh0KGi2XsBq5-cT6-3nPauxXqHnsHJnCFZ3CvJVkyuCQ0mFF9TZyCQ162WGvteLKfG197Y3iv_pz_fmS68Hxt8iPBPj5HscP8YvCNX7uhYCAAA=)):
@ -246,6 +246,23 @@ We can tighten things up further by declaring a generic, so that `data` and `row
</script>
```
## Exporting snippets
Snippets declared at the top level of a `.svelte` file can be exported from a `<script module>` for use in other components, provided they don't reference any declarations in a non-module `<script>` (whether directly or indirectly, via other snippets) ([demo](/playground/untitled#H4sIAAAAAAAAE3WPwY7CMAxEf8UyB1hRgdhjl13Bga8gHFJipEqtGyUGFUX5dxJUtEB3b9bYM_MckHVLWOKut50TMuC5tpbEY4GnuiGP5T6gXG0-ykLSB8vW2oW_UCNZq7Snv_Rjx0Kc4kpc-6OrrfwoVlK3uQ4CaGMgwsl1LUwXy0f54J9-KV4vf20cNo7YkMu22aqAz4-oOLUI9YKluDPF4h_at-hX5PFyzA1tZ84N3fGpf8YfUU6GvDumLqDKmEqCjjCHUEX4hqDTWCU5PJ6Or38c4g1cPu9tnAEAAA==)):
```svelte
<scriptmodule>
export { add };
</script>
{#snippet add(a, b)}
{a} + {b} = {a + b}
{/snippet}
```
> [!NOTE]
> This requires Svelte 5.5.0 or newer
## Programmatic snippets
Snippets can be created programmatically with the [`createRawSnippet`](svelte#createRawSnippet) API. This is intended for advanced use cases.
@ -53,6 +53,22 @@ In the case of a numeric input (`type="number"` or `type="range"`), the value wi
If the input is empty or invalid (in the case of `type="number"`), the value is `undefined`.
Since 5.6.0, if an `<input>` has a `defaultValue` and is part of a form, it will revert to that value instead of the empty string when the form is reset. Note that for the initial render the value of the binding takes precedence unless it is `null` or `undefined`.
```svelte
<script>
let value = $state('');
</script>
<form>
<inputbind:valuedefaultValue="not the empty string">
<inputtype="reset"value="Reset">
</form>
```
> [!NOTE]
> Use reset buttons sparingly, and ensure that users won't accidentally click them while trying to submit the form.
## `<input bind:checked>`
Checkbox and radio inputs can be bound with `bind:checked`:
@ -64,16 +80,29 @@ Checkbox and radio inputs can be bound with `bind:checked`:
</label>
```
Since 5.6.0, if an `<input>` has a `defaultChecked` attribute and is part of a form, it will revert to that value instead of `false` when the form is reset. Note that for the initial render the value of the binding takes precedence unless it is `null` or `undefined`.
<!-- grouped radio inputs are mutually exclusive -->
@ -146,6 +175,16 @@ When the value of an `<option>` matches its text content, the attribute can be o
</select>
```
You can give the `<select>` a default value by adding a `selected` attribute to the`<option>` (or options, in the case of `<select multiple>`) that should be initially selected. If the `<select>` is part of a form, it will revert to that selection when the form is reset. Note that for the initial render the value of the binding takes precedence if it's not `undefined`.
```svelte
<selectbind:value={selected}>
<optionvalue={a}>a</option>
<optionvalue={b}selected>b</option>
<optionvalue={c}>c</option>
</select>
```
## `<audio>`
`<audio>` elements have their own set of bindings — five two-way ones...
Boundaries allow you to guard against errors in part of your app from breaking the app as a whole, and to recover from those errors.
If an error occurs while rendering or updating the children of a `<svelte:boundary>`, or running any [`$effect`]($effect) functions contained therein, the contents will be removed.
Errors occurring outside the rendering process (for example, in event handlers) are _not_ caught by error boundaries.
## Properties
For the boundary to do anything, one or both of `failed` and `onerror` must be provided.
### `failed`
If a `failed` snippet is provided, it will be rendered with the error that was thrown, and a `reset` function that recreates the contents ([demo](/playground/hello-world#H4sIAAAAAAAAE3VRy26DMBD8lS2tFCIh6JkAUlWp39Cq9EBg06CAbdlLArL87zWGKk8ORnhmd3ZnrD1WtOjFXqKO2BDGW96xqpBD5gXerm5QefG39mgQY9EIWHxueRMinLosti0UPsJLzggZKTeilLWgLGc51a3gkuCjKQ7DO7cXZotgJ3kLqzC6hmex1SZnSXTWYHcrj8LJjWTk0PHoZ8VqIdCOKayPykcpuQxAokJaG1dGybYj4gw4K5u6PKTasSbjXKgnIDlA8VvUdo-pzonraBY2bsH7HAl78mKSHZpgIcuHjq9jXSpZSLixRlveKYQUXhQVhL6GPobXAAb7BbNeyvNUs4qfRg3OnELLj5hqH9eQZqCnoBwR9lYcQxuVXeBzc8kMF8yXY4yNJ5oGiUzP_aaf_waTRGJib5_Ad3P_vbCuaYxzeNpbU0eUMPAOKh7Yw1YErgtoXyuYlPLzc10_xo_5A91zkQL_AgAA)):
```svelte
<svelte:boundary>
<FlakyComponent/>
{#snippet failed(error, reset)}
<buttononclick={reset}>oops! try again</button>
{/snippet}
</svelte:boundary>
```
> [!NOTE]
> As with [snippets passed to components](snippet#Passing-snippets-to-components), the `failed` snippet can be passed explicitly as a property...
>
> ```svelte
> <svelte:boundary{failed}>...</svelte:boundary>
> ```
>
> ...or implicitly by declaring it directly inside the boundary, as in the example above.
### `onerror`
If an `onerror` function is provided, it will be called with the same two `error` and `reset` arguments. This is useful for tracking the error with an error reporting service...
```svelte
<svelte:boundaryonerror={(e)=> report(e)}>
...
</svelte:boundary>
```
...or using `error` and `reset` outside the boundary itself:
```svelte
<script>
let error = $state(null);
let reset = $state(() => {});
function onerror(e, r) {
error = e;
reset = r;
}
</script>
<svelte:boundary{onerror}>
<FlakyComponent/>
</svelte:boundary>
{#if error}
<buttononclick={()=> {
error = null;
reset();
}}>
oops! try again
</button>
{/if}
```
If an error occurs inside the `onerror` function (or if you rethrow the error), it will be handled by a parent boundary if such exists.
@ -40,26 +40,26 @@ If you want to use one of these features, you need to setup up a `script` prepro
To use non-type-only TypeScript features within Svelte components, you need to add a preprocessor that will turn TypeScript into JavaScript.
### Using SvelteKit or Vite
The easiest way to get started is scaffolding a new SvelteKit project by typing `npx sv create`, following the prompts and choosing the TypeScript option.
```ts
/// file: svelte.config.js
// @noErrors
import { vitePreprocess } from '@sveltejs/kit/vite';
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
const config = {
preprocess: vitePreprocess()
// Note the additional `{ script: true }`
preprocess: vitePreprocess({ script: true })
};
export default config;
```
If you don't need or want all the features SvelteKit has to offer, you can scaffold a Svelte-flavoured Vite project instead by typing `npm create vite@latest` and selecting the `svelte-ts` option.
### Using SvelteKit or Vite
The easiest way to get started is scaffolding a new SvelteKit project by typing `npx sv create`, following the prompts and choosing the TypeScript option.
```ts
/// file: svelte.config.js
// @noErrors
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
const config = {
@ -69,6 +69,8 @@ const config = {
export default config;
```
If you don't need or want all the features SvelteKit has to offer, you can scaffold a Svelte-flavoured Vite project instead by typing `npm create vite@latest` and selecting the `svelte-ts` option.
In both cases, a `svelte.config.js` with `vitePreprocess` will be added. Vite/SvelteKit will read from this config file.
### Other build tools
@ -77,6 +79,14 @@ If you're using tools like Rollup or Webpack instead, install their respective S
> [!NOTE] If you're starting a new project, we recommend using SvelteKit or Vite instead
## tsconfig.json settings
When using TypeScript, make sure your `tsconfig.json` is setup correctly.
- Use a [`target`](https://www.typescriptlang.org/tsconfig/#target) of at least `ES2022`, or a `target` of at least `ES2015` alongside [`useDefineForClassFields`](https://www.typescriptlang.org/tsconfig/#useDefineForClassFields). This ensures that rune declarations on class fields are not messed with, which would break the Svelte compiler
- Set [`verbatimModuleSyntax`](https://www.typescriptlang.org/tsconfig/#verbatimModuleSyntax) to `true` so that imports are left as-is
- Set [`isolatedModules`](https://www.typescriptlang.org/tsconfig/#isolatedModules) to `true` so that each file is looked at in isolation. TypeScript has a few features which require cross-file analysis and compilation, which the Svelte compiler and tooling like Vite don't do.
## Typing `$props`
Type `$props` just like a regular object with certain properties.
@ -102,6 +102,12 @@ If you need hash-based routing on the client side, check out [svelte-spa-router]
You can see a [community-maintained list of routers on sveltesociety.dev](https://sveltesociety.dev/packages?category=routers).
## How do I write a mobile app with Svelte?
While most mobile apps are written without using JavaScript, if you'd like to leverage your existing Svelte components and knowledge of Svelte when building mobile apps, you can turn a [SvelteKit SPA](https://kit.svelte.dev/docs/single-page-apps) into a mobile app with [Tauri](https://v2.tauri.app/start/frontend/sveltekit/) or [Capacitor](https://capacitorjs.com/solution/svelte). Mobile features like the camera, geolocation, and push notifications are available via plugins for both platforms.
Svelte Native was an option available for Svelte 4, but note that Svelte 5 does not currently support it. Svelte Native lets you write NativeScript apps using Svelte components that contain [NativeScript UI components](https://docs.nativescript.org/ui/) rather than DOM elements, which may be familiar for users coming from React Native.
## Can I tell Svelte not to remove my unused styles?
No. Svelte removes the styles from the component and warns you about them in order to prevent issues that would otherwise arise.
<!-- This file is generated by scripts/process-messages/index.js. Do not edit! -->
### assignment_value_stale
```
Assignment to `%property%` property (%location%) will evaluate to the right-hand side, not the value of `%property%` following the assignment. This may result in unexpected behaviour.
```
Given a case like this...
```svelte
<script>
let object = $state({ array: null });
function add() {
(object.array ??= []).push(object.array.length);
}
</script>
<buttononclick={add}>add</button>
<p>items: {JSON.stringify(object.items)}</p>
```
...the array being pushed to when the button is first clicked is the `[]` on the right-hand side of the assignment, but the resulting value of `object.array` is an empty state proxy. As a result, the pushed value will be discarded.
You can fix this by separating it into two statements:
```js
let object = { array: [0] };
// ---cut---
function add() {
object.array ??= [];
object.array.push(object.array.length);
}
```
### binding_property_non_reactive
```
@ -86,6 +120,46 @@ Mutating a value outside the component that created it is strongly discouraged.
%component% mutated a value owned by %owner%. This is strongly discouraged. Consider passing values to child components with `bind:`, or use a callback instead
```
### reactive_declaration_non_reactive_property
```
A `$:` statement (%location%) read reactive state that was not visible to the compiler. Updates to this state will not cause the statement to re-run. The behaviour of this code will change if you migrate it to runes mode
```
In legacy mode, a `$:` [reactive statement](https://svelte.dev/docs/svelte/legacy-reactive-assignments) re-runs when the state it _references_ changes. This is determined at compile time, by analysing the code.
In runes mode, effects and deriveds re-run when there are changes to the values that are read during the function's _execution_.
Often, the result is the same — for example these can be considered equivalent:
```js
let a = 1, b = 2, sum = 3;
// ---cut---
$: sum = a + b;
```
```js
let a = 1, b = 2;
// ---cut---
const sum = $derived(a + b);
```
In some cases — such as the one that triggered the above warning — they are _not_ the same:
```js
let a = 1, b = 2, sum = 3;
// ---cut---
const add = () => a + b;
// the compiler can't 'see' that `sum` depends on `a` and `b`, but
// they _would_ be read while executing the `$derived` version
$: sum = add();
```
Similarly, reactive properties of [deep state](https://svelte.dev/docs/svelte/$state#Deep-state) are not visible to the compiler. As such, changes to these properties will cause effects and deriveds to re-run but will _not_ cause `$:` statements to re-run.
When you [migrate this component](https://svelte.dev/docs/svelte/v5-migration-guide) to runes mode, the behaviour will change accordingly.
@ -481,12 +487,12 @@ A component cannot have a default export
### node_invalid_placement
```
%thing% is invalid inside `<%parent%>`
%message%. The browser will 'repair' the HTML (by moving, removing, or inserting elements) which breaks Svelte's assumptions about the structure of your components.
```
HTML restricts where certain elements can appear. In case of a violation the browser will 'repair' the HTML in a way that breaks Svelte's assumptions about the structure of your components. Some examples:
- `<p>hello <div>world</div></p>` will result in `<p>hello </p><div>world</div><p></p>`for example (the `<div>` autoclosed the `<p>` because `<p>` cannot contain block-level elements)
- `<p>hello <div>world</div></p>` will result in `<p>hello </p><div>world</div><p></p>` (the `<div>` autoclosed the `<p>` because `<p>` cannot contain block-level elements)
- `<option><div>option a</div></option>` will result in `<option>option a</option>` (the `<div>` is removed)
- `<table><tr><td>cell</td></tr></table>` will result in `<table><tbody><tr><td>cell</td></tr></tbody></table>` (a `<tbody>` is auto-inserted)
@ -694,6 +700,30 @@ Cannot use `<slot>` syntax and `{@render ...}` tags in the same component. Migra
Cannot use explicit children snippet at the same time as implicit children content. Remove either the non-whitespace content or the children snippet block
```
### snippet_invalid_export
```
An exported snippet can only reference things declared in a `<script module>`, or other exportable snippets
```
It's possible to export a snippet from a `<script module>` block, but only if it doesn't reference anything defined inside a non-module-level `<script>`. For example you can't do this...
```svelte
<scriptmodule>
export { greeting };
</script>
<script>
let message = 'hello';
</script>
{#snippet greeting(name)}
<p>{message} {name}!</p>
{/snippet}
```
...because `greeting` references `message`, which is defined in the second `<script>`.
### snippet_invalid_rest_parameter
```
@ -762,6 +792,18 @@ A component can have a single top-level `<style>` element
`<svelte:body>` does not support non-event attributes or spread attributes
```
### svelte_boundary_invalid_attribute
```
Valid attributes on `<svelte:boundary>` are `onerror` and `failed`
@ -643,12 +643,12 @@ Svelte 5 components are no longer classes. Instantiate them using `mount` or `hy
### node_invalid_placement_ssr
```
%thing% is invalid inside `<%parent%>`. When rendering this component on the server, the resulting HTML will be modified by the browser, likely resulting in a `hydration_mismatch` warning
%message%. When rendering this component on the server, the resulting HTML will be modified by the browser (by moving, removing, or inserting elements), likely resulting in a `hydration_mismatch` warning
```
HTML restricts where certain elements can appear. In case of a violation the browser will 'repair' the HTML in a way that breaks Svelte's assumptions about the structure of your components. Some examples:
- `<p>hello <div>world</div></p>` will result in `<p>hello </p><div>world</div><p></p>`for example (the `<div>` autoclosed the `<p>` because `<p>` cannot contain block-level elements)
- `<p>hello <div>world</div></p>` will result in `<p>hello </p><div>world</div><p></p>` (the `<div>` autoclosed the `<p>` because `<p>` cannot contain block-level elements)
- `<option><div>option a</div></option>` will result in `<option>option a</option>` (the `<div>` is removed)
- `<table><tr><td>cell</td></tr></table>` will result in `<table><tbody><tr><td>cell</td></tr></tbody></table>` (a `<tbody>` is auto-inserted)
@ -726,12 +726,6 @@ Reactive declarations only exist at the top level of the instance script
Reassignments of module-level declarations will not cause reactive statements to update
```
### reactive_declaration_non_reactive_property
```
Properties of objects and arrays are not reactive unless in runes mode. Changes to this property will not cause the reactive statement to update
@ -74,39 +74,45 @@ If no slotted content is provided, a component can define fallback content by pu
Slots can be rendered zero or more times and can pass values _back_ to the parent using props. The parent exposes the values to the slot template using the `let:` directive.
The usual shorthand rules apply — `let:item` is equivalent to `let:item={item}`, and `<slot {item}>` is equivalent to `<slot item={item}>`.
```svelte
<!-- FancyList.svelte -->
<!--- file: FancyList.svelte --->
<ul>
{#each items as item}
{#each items as data}
<liclass="fancy">
<slotprop={item}/>
<!-- 'item' here... -->
<slotitem={process(data)}/>
</li>
{/each}
</ul>
```
<!-- App.svelte -->
<FancyList{items}let:prop={thing}>
<div>{thing.text}</div>
```svelte
<!--- file: App.svelte --->
<!-- ...corresponds to 'item' here: -->
<FancyList{items}let:item={processed}>
<div>{processed.text}</div>
</FancyList>
```
The usual shorthand rules apply — `let:item` is equivalent to `let:item={item}`, and `<slot {item}>` is equivalent to `<slot item={item}>`.
Named slots can also expose values. The `let:` directive goes on the element with the `slot` attribute.
- fix: ensure bindings always take precedence over spreads ([#14575](https://github.com/sveltejs/svelte/pull/14575))
## 5.7.0
### Minor Changes
- feat: add `createSubscriber` function for creating reactive values that depend on subscriptions ([#14422](https://github.com/sveltejs/svelte/pull/14422))
- feat: add reactive `MediaQuery` class, and a `prefersReducedMotion` class instance ([#14422](https://github.com/sveltejs/svelte/pull/14422))
### Patch Changes
- fix: treat `undefined` and `null` the same for the initial input value ([#14562](https://github.com/sveltejs/svelte/pull/14562))
## 5.6.2
### Patch Changes
- chore: make if blocks tree-shakable ([#14549](https://github.com/sveltejs/svelte/pull/14549))
## 5.6.1
### Patch Changes
- fix: handle static form values in combination with default values ([#14555](https://github.com/sveltejs/svelte/pull/14555))
## 5.6.0
### Minor Changes
- feat: support `defaultValue/defaultChecked` for inputs ([#14289](https://github.com/sveltejs/svelte/pull/14289))
## 5.5.4
### Patch Changes
- fix: better error messages for invalid HTML trees ([#14445](https://github.com/sveltejs/svelte/pull/14445))
- fix: remove spreaded event handlers when they become nullish ([#14546](https://github.com/sveltejs/svelte/pull/14546))
- fix: respect the unidirectional nature of time ([#14541](https://github.com/sveltejs/svelte/pull/14541))
## 5.5.3
### Patch Changes
- fix: don't try to add owners to non-`$state` class fields ([#14533](https://github.com/sveltejs/svelte/pull/14533))
- fix: capture infinite_loop_guard in error boundary ([#14534](https://github.com/sveltejs/svelte/pull/14534))
- fix: proxify values when assigning using `||=`, `&&=` and `??=` operators ([#14273](https://github.com/sveltejs/svelte/pull/14273))
## 5.5.2
### Patch Changes
- fix: use correct reaction when lazily creating deriveds inside `SvelteDate` ([#14525](https://github.com/sveltejs/svelte/pull/14525))
## 5.5.1
### Patch Changes
- fix: don't throw with nullish actions ([#13559](https://github.com/sveltejs/svelte/pull/13559))
- fix: leave update expressions untransformed unless a transformer is provided ([#14507](https://github.com/sveltejs/svelte/pull/14507))
- chore: turn reactive_declaration_non_reactive_property into a runtime warning ([#14192](https://github.com/sveltejs/svelte/pull/14192))
## 5.5.0
### Minor Changes
- feat: allow snippets to be exported from module scripts ([#14315](https://github.com/sveltejs/svelte/pull/14315))
### Patch Changes
- fix: ignore TypeScript generics on variables ([#14509](https://github.com/sveltejs/svelte/pull/14509))
## 5.4.0
### Minor Changes
- feat: support `#each` without `as` ([#14396](https://github.com/sveltejs/svelte/pull/14396))
## 5.3.2
### Patch Changes
- fix: correctly prune CSS for elements inside snippets ([#14494](https://github.com/sveltejs/svelte/pull/14494))
- fix: render attributes during SSR regardless of case ([#14492](https://github.com/sveltejs/svelte/pull/14492))
## 5.3.1
### Patch Changes
- fix: treat spread elements the same as call expressions ([#14488](https://github.com/sveltejs/svelte/pull/14488))
> Assignment to `%property%` property (%location%) will evaluate to the right-hand side, not the value of `%property%` following the assignment. This may result in unexpected behaviour.
Given a case like this...
```svelte
<script>
let object = $state({ array: null });
function add() {
(object.array ??= []).push(object.array.length);
}
</script>
<buttononclick={add}>add</button>
<p>items: {JSON.stringify(object.items)}</p>
```
...the array being pushed to when the button is first clicked is the `[]` on the right-hand side of the assignment, but the resulting value of `object.array` is an empty state proxy. As a result, the pushed value will be discarded.
You can fix this by separating it into two statements:
```js
let object = { array: [0] };
// ---cut---
function add() {
object.array ??= [];
object.array.push(object.array.length);
}
```
## binding_property_non_reactive
> `%binding%` is binding to a non-reactive property
@ -54,6 +86,44 @@ The easiest way to log a value as it changes over time is to use the [`$inspect`
> %component% mutated a value owned by %owner%. This is strongly discouraged. Consider passing values to child components with `bind:`, or use a callback instead
## reactive_declaration_non_reactive_property
> A `$:` statement (%location%) read reactive state that was not visible to the compiler. Updates to this state will not cause the statement to re-run. The behaviour of this code will change if you migrate it to runes mode
In legacy mode, a `$:` [reactive statement](https://svelte.dev/docs/svelte/legacy-reactive-assignments) re-runs when the state it _references_ changes. This is determined at compile time, by analysing the code.
In runes mode, effects and deriveds re-run when there are changes to the values that are read during the function's _execution_.
Often, the result is the same — for example these can be considered equivalent:
```js
let a = 1, b = 2, sum = 3;
// ---cut---
$: sum = a + b;
```
```js
let a = 1, b = 2;
// ---cut---
const sum = $derived(a + b);
```
In some cases — such as the one that triggered the above warning — they are _not_ the same:
```js
let a = 1, b = 2, sum = 3;
// ---cut---
const add = () => a + b;
// the compiler can't 'see' that `sum` depends on `a` and `b`, but
// they _would_ be read while executing the `$derived` version
$: sum = add();
```
Similarly, reactive properties of [deep state](https://svelte.dev/docs/svelte/$state#Deep-state) are not visible to the compiler. As such, changes to these properties will cause effects and deriveds to re-run but will _not_ cause `$:` statements to re-run.
When you [migrate this component](https://svelte.dev/docs/svelte/v5-migration-guide) to runes mode, the behaviour will change accordingly.
## state_proxy_equality_mismatch
> Reactive `$state(...)` proxies and the values they proxy have different identities. Because of this, comparisons with `%operator%` will produce unexpected results
> `$effect()` can only be used as an expression statement
## export_undefined
> `%name%` is not defined
## global_reference_invalid
> `%name%` is an illegal variable name. To reference a global variable called `%name%`, use `globalThis.%name%`
@ -134,6 +138,28 @@
> %name% cannot be used in runes mode
## snippet_invalid_export
> An exported snippet can only reference things declared in a `<script module>`, or other exportable snippets
It's possible to export a snippet from a `<script module>` block, but only if it doesn't reference anything defined inside a non-module-level `<script>`. For example you can't do this...
```svelte
<scriptmodule>
export { greeting };
</script>
<script>
let message = 'hello';
</script>
{#snippet greeting(name)}
<p>{message} {name}!</p>
{/snippet}
```
...because `greeting` references `message`, which is defined in the second `<script>`.
> %message%. The browser will 'repair' the HTML (by moving, removing, or inserting elements) which breaks Svelte's assumptions about the structure of your components.
HTML restricts where certain elements can appear. In case of a violation the browser will 'repair' the HTML in a way that breaks Svelte's assumptions about the structure of your components. Some examples:
- `<p>hello <div>world</div></p>` will result in `<p>hello </p><div>world</div><p></p>`for example (the `<div>` autoclosed the `<p>` because `<p>` cannot contain block-level elements)
- `<p>hello <div>world</div></p>` will result in `<p>hello </p><div>world</div><p></p>` (the `<div>` autoclosed the `<p>` because `<p>` cannot contain block-level elements)
- `<option><div>option a</div></option>` will result in `<option>option a</option>` (the `<div>` is removed)
- `<table><tr><td>cell</td></tr></table>` will result in `<table><tbody><tr><td>cell</td></tr></tbody></table>` (a `<tbody>` is auto-inserted)
@ -282,6 +282,14 @@ HTML restricts where certain elements can appear. In case of a violation the bro
> `<svelte:body>` does not support non-event attributes or spread attributes
## svelte_boundary_invalid_attribute
> Valid attributes on `<svelte:boundary>` are `onerror` and `failed`
## svelte_boundary_invalid_attribute_value
> Attribute value must be a non-string expression
## svelte_component_invalid_this
> Invalid component definition — must be an `{expression}`
> %thing% is invalid inside `<%parent%>`. When rendering this component on the server, the resulting HTML will be modified by the browser, likely resulting in a `hydration_mismatch` warning
> %message%. When rendering this component on the server, the resulting HTML will be modified by the browser (by moving, removing, or inserting elements), likely resulting in a `hydration_mismatch` warning
HTML restricts where certain elements can appear. In case of a violation the browser will 'repair' the HTML in a way that breaks Svelte's assumptions about the structure of your components. Some examples:
- `<p>hello <div>world</div></p>` will result in `<p>hello </p><div>world</div><p></p>`for example (the `<div>` autoclosed the `<p>` because `<p>` cannot contain block-level elements)
- `<p>hello <div>world</div></p>` will result in `<p>hello </p><div>world</div><p></p>` (the `<div>` autoclosed the `<p>` because `<p>` cannot contain block-level elements)
- `<option><div>option a</div></option>` will result in `<option>option a</option>` (the `<div>` is removed)
- `<table><tr><td>cell</td></tr></table>` will result in `<table><tbody><tr><td>cell</td></tr></tbody></table>` (a `<tbody>` is auto-inserted)
e(node,"node_invalid_placement",`${message}. The browser will 'repair' the HTML (by moving, removing, or inserting elements) which breaks Svelte's assumptions about the structure of your components.`);
}
/**
@ -1228,6 +1246,24 @@ export function svelte_body_illegal_attribute(node) {
e(node,"svelte_body_illegal_attribute","`<svelte:body>` does not support non-event attributes or spread attributes");
w(node,"reactive_declaration_non_reactive_property","Properties of objects and arrays are not reactive unless in runes mode. Changes to this property will not cause the reactive statement to update");
w(node,"node_invalid_placement_ssr",`${thing} is invalid inside \`<${parent}>\`. When rendering this component on the server, the resulting HTML will be modified by the browser, likely resulting in a \`hydration_mismatch\` warning`);
w(node,"node_invalid_placement_ssr",`${message}. When rendering this component on the server, the resulting HTML will be modified by the browser (by moving, removing, or inserting elements), likely resulting in a \`hydration_mismatch\` warning`);
console.warn(`%c[svelte] assignment_value_stale\n%cAssignment to \`${property}\` property (${location}) will evaluate to the right-hand side, not the value of \`${property}\` following the assignment. This may result in unexpected behaviour.`,bold,normal);
console.warn(`%c[svelte] reactive_declaration_non_reactive_property\n%cA \`$:\` statement (${location}) read reactive state that was not visible to the compiler. Updates to this state will not cause the statement to re-run. The behaviour of this code will change if you migrate it to runes mode`,bold,normal);
*A[mediaquery](https://svelte.dev/docs/svelte/svelte-reactivity#MediaQuery) that matches if the user [prefers reduced motion](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-reduced-motion).