chore: restructure docs for new site (#13699)

pull/13752/head
Rich Harris 2 weeks ago committed by GitHub
parent ad578a5da5
commit fd78385447
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -1,6 +1,4 @@
# Temporarily ignore this file to avoid merge conflicts.
# see: https://github.com/sveltejs/svelte/pull/9609
documentation/docs/05-misc/03-typescript.md
documentation/docs/
packages/**/dist/*.js
packages/**/build/*.js

@ -16,7 +16,7 @@ We think it'll give you a much nicer development experience — one that also sc
## Try it now
You can start a new Svelte TypeScript project using Svelte's official scaffolding CLI by running `npm create svelte@latest` and following the prompts. This sets up a new SvelteKit project for you.
You can start a new Svelte TypeScript project using Svelte's official scaffolding CLI by running `npx sv create` and following the prompts. This sets up a new SvelteKit project for you.
Alternatively you can run `npm create vite@latest myapp -- --template svelte-ts` to scaffold a Vite project using Svelte and TypeScript.

@ -9,7 +9,7 @@ After two years in development, [SvelteKit](https://kit.svelte.dev) has finally
Were so excited to share this release with you. Its the culmination of thousands of hours of work, both from the Svelte core team and the wider community, and we think its the most enjoyable way to build production-grade websites, whether youre a solo developer working on a small project or part of a large team.
To get started, run `npm create svelte@latest`, and visit the [docs](https://kit.svelte.dev/docs) and (experimental!) [interactive tutorial](https://learn.svelte.dev).
To get started, run `npm sv create`, and visit the [docs](https://kit.svelte.dev/docs) and (experimental!) [interactive tutorial](https://learn.svelte.dev).
<div class="max">
<figure style="max-width: 960px; margin: 0 auto">

@ -9,7 +9,7 @@ After months in the making, we're excited to announce the stable release of Svel
Time flies - Svelte 3 was released more than four years ago! In JavaScript-framework-time, that's eons. Sveltes freshness has persisted throughout, but Node.js and browser APIs have evolved during that time and today were updating Svelte to take advantage of some of these improvements. Svelte 4 is mainly a maintenance release, bumping minimum version requirements and tightening up the design in specific areas. It sets the stage for the next generation of Svelte to be released as Svelte 5 - we think youll love it.
If you haven't tried Svelte yet, take it for a spin in our [interactive tutorial](https://learn.svelte.dev/), on [StackBlitz](https://sveltekit.new/), or locally with `npm create svelte@latest`. Svelte lets you easily put together web UIs leveraging the power of HTML, CSS, JS, and the Svelte compiler. Watch [Svelte Radio Live](https://www.youtube.com/watch?v=72TIVhRtyWE) to learn more about this release.
If you haven't tried Svelte yet, take it for a spin in our [interactive tutorial](https://learn.svelte.dev/), on [StackBlitz](https://sveltekit.new/), or locally with `npx sv create`. Svelte lets you easily put together web UIs leveraging the power of HTML, CSS, JS, and the Svelte compiler. Watch [Svelte Radio Live](https://www.youtube.com/watch?v=72TIVhRtyWE) to learn more about this release.
## What's new
@ -40,7 +40,7 @@ Stay tuned for a more in-depth blog post about all the site changes in the comin
## Migrating
Most apps and libraries that are compatible with Svelte 3 should be compatible with Svelte 4. Library authors will need to update the version range to include Svelte 4 if `svelte` is specified in the `peerDependencies`. For application authors, the most common change required will be updating tooling to meet the new minimum version requirements such as Node.js 16. Many other migration steps can be handled with `npx svelte-migrate@latest svelte-4`.
Most apps and libraries that are compatible with Svelte 3 should be compatible with Svelte 4. Library authors will need to update the version range to include Svelte 4 if `svelte` is specified in the `peerDependencies`. For application authors, the most common change required will be updating tooling to meet the new minimum version requirements such as Node.js 16. Many other migration steps can be handled with `npx sv migrate svelte-4`.
Read the [migration guide](/docs/v4-migration-guide) for full details.

@ -54,7 +54,7 @@ With that out of the way, let's see how you can use view transitions in your Sve
## Getting started with view transitions
The best way to see view transitions in action is to try it yourself. You can spin up the SvelteKit demo app by running `npm create svelte@latest` in your local terminal, or in your browser on [StackBlitz](https://sveltekit.new). Make sure to use a browser that supports the view transitions API. Once you have the app running, add the following to the script block in `src/routes/+layout.svelte`.
The best way to see view transitions in action is to try it yourself. You can spin up the SvelteKit demo app by running `npx sv create` in your local terminal, or in your browser on [StackBlitz](https://sveltekit.new). Make sure to use a browser that supports the view transitions API. Once you have the app running, add the following to the script block in `src/routes/+layout.svelte`.
```js
// @errors: 2305 7006 2339 2810

@ -2,29 +2,29 @@
title: Overview
---
- Short intro to what Svelte is and why it's the best ever
- A few code examples to have a very rough understanding of how Svelte code looks like
- Jump off points to tutorial, SvelteKit etc
Svelte is a web UI framework that uses a compiler to turn declarative component code like this...
Svelte is a framework for building user interfaces on the web. It uses a compiler to turn declarative components written in HTML, CSS and JavaScript...
```svelte
<!--- file: App.svelte --->
<script lang="ts">
let count = $state(0);
function increment() {
count += 1;
<script>
function greet() {
alert('Welcome to Svelte!');
}
</script>
<button onclick={increment}>
clicks: {count}
</button>
<button onclick={greet}>click me</button>
<style>
button {
font-size: 2em;
}
</style>
```
...into tightly optimized JavaScript that updates the document when state like count changes. Because the compiler can 'see' where count is referenced, the generated code is highly efficient, and because we're hijacking syntax like `$state(...)` and `=` instead of using cumbersome APIs, you can write less code.
...into lean, tightly optimized JavaScript.
You can use it to build anything on the web, from standalone components to ambitious full stack apps (using Svelte's companion application framework, [SvelteKit](../kit)) and everything in between.
Besides being fun to work with, Svelte offers a lot of features built-in, such as animations and transitions. Once you've written your first components you can reach for our batteries included metaframework [SvelteKit](../kit) which provides you with an opinionated router, data loading and more.
These pages serve as reference documentation. If you're new to Svelte, we recommend starting with the [interactive tutorial](/tutorial) and coming back here when you have questions.
If you're new to Svelte, visit the [interactive tutorial](/tutorial) before consulting this documentation. You can try Svelte online using the [REPL](/repl). Alternatively, if you'd like a more fully-featured environment, you can try Svelte on [StackBlitz](https://sveltekit.new).
You can also try Svelte online in the [playground](/playground) or, if you need a more fully-featured environment, on [StackBlitz](https://sveltekit.new).

@ -2,37 +2,27 @@
title: Getting started
---
- `npm create svelte@latest`, describe that it scaffolds SvelteKit project
- `npm create vite@latest`, describe that it scaffolds Svelte SPA powered by Vite
- mention `svelte-add`
- Jump off points to tutorial, SvelteKit etc
## Start a new project
We recommend using [SvelteKit](https://kit.svelte.dev/), the official application framework from the Svelte team:
We recommend using [SvelteKit](https://kit.svelte.dev/), the official application framework from the Svelte team powered by [Vite](https://vite.dev/):
```
npm create svelte@latest myapp
npx sv create myapp
cd myapp
npm install
npm run dev
```
SvelteKit will handle calling [the Svelte compiler](https://www.npmjs.com/package/svelte) to convert your `.svelte` files into `.js` files that create the DOM and `.css` files that style it. It also provides all the other pieces you need to build a web application such as a development server, routing, deployment, and SSR support. [SvelteKit](https://kit.svelte.dev/) uses [Vite](https://vitejs.dev/) to build your code.
Don't worry if you don't know Svelte yet! You can ignore all the nice features SvelteKit brings on top for now and dive into it later.
### Alternatives to SvelteKit
If you don't want to use SvelteKit for some reason, you can also use Svelte with Vite (but without SvelteKit) by running `npm create vite@latest` and selecting the `svelte` option. With this, `npm run build` will generate HTML, JS and CSS files inside the `dist` directory thanks using [vite-plugin-svelte](https://github.com/sveltejs/vite-plugin-svelte). In most cases, you will probably need to [choose a routing library](faq#Is-there-a-router) as well.
You can also use Svelte directly with Vite by running `npm create vite@latest` and selecting the `svelte` option. With this, `npm run build` will generate HTML, JS and CSS files inside the `dist` directory using [vite-plugin-svelte](https://github.com/sveltejs/vite-plugin-svelte). In most cases, you will probably need to [choose a routing library](faq#Is-there-a-router) as well.
Alternatively, there are plugins for [Rollup](https://github.com/sveltejs/rollup-plugin-svelte), [Webpack](https://github.com/sveltejs/svelte-loader) [and a few others](https://sveltesociety.dev/packages?category=build-plugins) to handle Svelte compilation — which will output `.js` and `.css` that you can insert into your HTML — but setting up SSR with them requires more manual work.
There are also plugins for [Rollup](https://github.com/sveltejs/rollup-plugin-svelte), [Webpack](https://github.com/sveltejs/svelte-loader) [and a few others](https://sveltesociety.dev/packages?category=build-plugins), but we recommend Vite.
## Editor tooling
The Svelte team maintains a [VS Code extension](https://marketplace.visualstudio.com/items?itemName=svelte.svelte-vscode) and there are integrations with various other [editors](https://sveltesociety.dev/resources#editor-support) and tools as well.
You can also check your code from the command line using [svelte-check](https://www.npmjs.com/package/svelte-check) (using the Svelte or Vite CLI setup will install this for you).
You can also check your code from the command line using [sv check](https://github.com/sveltejs/cli).
## Getting help

@ -0,0 +1,66 @@
---
title: .svelte files
---
Components are the building blocks of Svelte applications. They are written into `.svelte` files, using a superset of HTML.
All three sections — script, styles and markup — are optional.
<!-- prettier-ignore -->
```svelte
/// file: MyComponent.svelte
<script module>
// module-level logic goes here
// (you will rarely use this)
</script>
<script>
// instance-level logic goes here
</script>
<!-- markup (zero or more items) goes here -->
<style>
/* styles go here */
</style>
```
## `<script>`
A `<script>` block contains JavaScript (or TypeScript, when adding the `lang="ts"` attribute) that runs when a component instance is created. Variables declared (or imported) at the top level can be referenced in the component's markup.
In addition to normal JavaScript, you can use _runes_ to declare [component props]($props) and add reactivity to your component. Runes are covered in the next section.
<!-- TODO describe behaviour of `export` -->
## `<script module>`
A `<script>` tag with a `module` attribute runs once when the module first evaluates, rather than for each component instance. Variables declared in this block can be referenced elsewhere in the component, but not vice versa.
```svelte
<script module>
let total = 0;
</script>
<script>
total += 1;
console.log(`instantiated ${total} times`);
</script>
```
You can `export` bindings from this block, and they will become exports of the compiled module. You cannot `export default`, since the default export is the component itself.
## `<style>`
CSS inside a `<style>` block will be scoped to that component.
```svelte
<style>
p {
/* this will only affect <p> elements in this component */
color: burlywood;
}
</style>
```
For more information regarding styling, read the documentation around [styles and classes](styles-and-classes).

@ -0,0 +1,7 @@
---
title: .svelte.js and .svelte.ts files
---
Besides `.svelte` files, Svelte also operates on `.svelte.js` and `.svelte.ts` files.
These behave like any other `.js` or `.ts` module, except that you can use runes. This is useful for creating reusable reactive logic, or sharing reactive state across your app.

@ -1,30 +1,7 @@
---
title: Component fundamentals
title: Public API of a component
---
- script (module) / template / style (rough overview)
- `$props` / `$state` (in the context of components)
Components are the building blocks of Svelte applications. They are written into `.svelte` files, using a superset of HTML.
All three sections — script, styles and markup — are optional.
```svelte
<script>
// logic goes here
</script>
<!-- markup (zero or more items) goes here -->
<style>
/* styles go here */
</style>
```
## `<script>`
A `<script>` block contains JavaScript (or TypeScript, when adding the `lang="ts"` attribute) that runs when a component instance is created. Variables declared (or imported) at the top level are 'visible' from the component's markup.
### Public API of a component
Svelte uses the `$props` rune to declare _properties_ or _props_, which means describing the public interface of the component which becomes accessible to consumers of the component.
@ -160,43 +137,3 @@ If you'd like to react to changes to a prop, use the `$derived` or `$effect` run
```
For more information on reactivity, read the documentation around runes.
## `<script module>`
A `<script>` tag with a `module` attribute runs once when the module first evaluates, rather than for each component instance. Values declared in this block are accessible from a regular `<script>` (and the component markup) but not vice versa.
You can `export` bindings from this block, and they will become exports of the compiled module.
You cannot `export default`, since the default export is the component itself.
```svelte
<script module>
let totalComponents = 0;
// the export keyword allows this function to imported with e.g.
// `import Example, { alertTotal } from './Example.svelte'`
export function alertTotal() {
alert(totalComponents);
}
</script>
<script>
totalComponents += 1;
console.log(`total number of times this component has been created: ${totalComponents}`);
</script>
```
## `<style>`
CSS inside a `<style>` block will be scoped to that component.
```svelte
<style>
p {
/* this will only affect <p> elements in this component */
color: burlywood;
}
</style>
```
For more information regarding styling, read the documentation around [styles and classes](styles-and-classes).

@ -0,0 +1,21 @@
---
title: What are runes?
---
> [!NOTE] **rune** /ro͞on/ _noun_
>
> A letter or mark used as a mystical or magic symbol.
Runes are symbols that you use in `.svelte` and `.svelte.js`/`.svelte.ts` files to control the Svelte compiler. If you think of Svelte as a language, runes are part of the syntax — they are _keywords_.
Runes have a `$` prefix and look like functions:
```js
let message = $state('hello');
```
They differ from normal JavaScript functions in important ways, however:
- You don't need to import them — they are part of the language
- They're not values — you can't assign them to a variable or pass them as arguments to a function
- Just like JavaScript keywords, they are only valid in certain positions (the compiler will help you if you put them in the wrong place)

@ -0,0 +1,127 @@
---
title: $state
---
The `$state` rune allows you to create _reactive state_, which means that your UI _reacts_ when it changes.
```svelte
<script>
let count = $state(0);
</script>
<button onclick={() => count++}>
clicks: {count}
</button>
```
Unlike other frameworks you may have encountered, there is no API for interacting with state — `count` is just a number, rather than an object or a function, and you can update it like you would update any other variable.
### Deep state
If `$state` is used with an array or a simple object, the result is a deeply reactive _state proxy_. [Proxies](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy) allow Svelte to run code when you read or write properties, including via methods like `array.push(...)`, triggering granular updates.
State is proxified recursively until Svelte finds something other than an array or simple object. In a case like this...
```js
let todos = $state([
{
done: false,
text: 'add more todos'
}
]);
```
...modifying an individual todo's property will trigger updates to anything in your UI that depends on that specific property:
```js
// @filename: ambient.d.ts
declare global {
const todos: Array<{ done: boolean, text: string }>
}
// @filename: index.js
// ---cut---
todos[0].done = !todos[0].done;
```
If you push a new object to the array, it will also be proxified:
```js
// @filename: ambient.d.ts
declare global {
const todos: Array<{ done: boolean, text: string }>
}
// @filename: index.js
// ---cut---
todos.push({
done: false,
text: 'eat lunch'
});
```
> [!NOTE] When you update properties of proxies, the original object is _not_ mutated.
### Classes
You can also use `$state` in class fields (whether public or private):
```js
// @errors: 7006 2554
class Todo {
done = $state(false);
text = $state();
constructor(text) {
this.text = text;
}
reset() {
this.text = '';
this.done = false;
}
}
```
> [!NOTE] The compiler transforms `done` and `text` into `get`/`set` methods on the class prototype referencing private fields.
## `$state.raw`
In cases where you don't want objects and arrays to be deeply reactive you can use `$state.raw`.
State declared with `$state.raw` cannot be mutated; it can only be _reassigned_. In other words, rather than assigning to a property of an object, or using an array method like `push`, replace the object or array altogether if you'd like to update it:
```js
let person = $state.raw({
name: 'Heraclitus',
age: 49
});
// this will have no effect
person.age += 1;
// this will work, because we're creating a new person
person = {
name: 'Heraclitus',
age: 50
};
```
This can improve performance with large arrays and objects that you weren't planning to mutate anyway, since it avoids the cost of making them reactive. Note that raw state can _contain_ reactive state (for example, a raw array of reactive objects).
## `$state.snapshot`
To take a static snapshot of a deeply reactive `$state` proxy, use `$state.snapshot`:
```svelte
<script>
let counter = $state({ count: 0 });
function onclick() {
// Will log `{ count: ... }` rather than `Proxy { ... }`
console.log($state.snapshot(counter));
}
</script>
```
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`.

@ -0,0 +1,45 @@
---
title: $derived
---
Derived state is declared with the `$derived` rune:
```svelte
<script>
let count = $state(0);
let doubled = $derived(count * 2);
</script>
<button onclick={() => count++}>
{doubled}
</button>
<p>{count} doubled is {doubled}</p>
```
The expression inside `$derived(...)` should be free of side-effects. Svelte will disallow state changes (e.g. `count++`) inside derived expressions.
As with `$state`, you can mark class fields as `$derived`.
## `$derived.by`
Sometimes you need to create complex derivations that don't fit inside a short expression. In these cases, you can use `$derived.by` which accepts a function as its argument.
```svelte
<script>
let numbers = $state([1, 2, 3]);
let total = $derived.by(() => {
let total = 0;
for (const n of numbers) {
total += n;
}
return total;
});
</script>
<button onclick={() => numbers.push(numbers.length + 1)}>
{numbers.join(' + ')} = {total}
</button>
```
In essence, `$derived(expression)` is equivalent to `$derived.by(() => expression)`.

@ -1,15 +1,16 @@
---
title: Side effects
title: $effect
---
- `$effect` (.pre)
- when not to use it, better patterns for what to do instead
Effects are what make your application _do things_. When Svelte runs an effect function, it tracks which pieces of state (and derived state) are accessed, and re-runs the function when that state later changes.
Side effects play a crucial role in applications. They are triggered by state changes and can then interact with external systems, like logging something, setting up a server connection or synchronize with a third-party library that has no knowledge of Svelte's reactivity model.
Most of the effects in a Svelte app are created by Svelte itself — they're the bits that update the text in `<h1>hello {name}!</h1>` when `name` changes, for example.
## `$effect` fundamentals
But you can also create your own effects with the `$effect` rune, which is useful when you need to synchronize an external system (whether that's a library, or a `<canvas>` element, or something across a network) with state inside your Svelte app.
To run _side-effects_ when the component is mounted to the DOM, and when values change, we can use the `$effect` rune ([demo](/#H4sIAAAAAAAAE31T24rbMBD9lUG7kAQ2sbdlX7xOYNk_aB_rQhRpbAsU2UiTW0P-vbrYubSlYGzmzMzROTPymdVKo2PFjzMzfIusYB99z14YnfoQuD1qQh-7bmdFQEonrOppVZmKNBI49QthCc-OOOH0LZ-9jxnR6c7eUpOnuv6KeT5JFdcqbvbcBcgDz1jXKGg6ncFyBedYR6IzLrAZwiN5vtSxaJA-EzadfJEjKw11C6GR22-BLH8B_wxdByWpvUYtqqal2XB6RVkG1CoHB6U1WJzbnYFDiwb3aGEdDa3Bm1oH12sQLTcNPp7r56m_00mHocSG97_zd7ICUXonA5fwKbPbkE2ZtMJGGVkEdctzQi4QzSwr9prnFYNk5hpmqVuqPQjNnfOJoMF22lUsrq_UfIN6lfSVyvQ7grB3X2mjMZYO3XO9w-U5iLx42qg29md3BP_ni5P4gy9ikTBlHxjLzAtPDlyYZmRdjAbGq7HprEQ7p64v4LU_guu0kvAkhBim3nMplWl8FreQD-CW20aZR0wq12t-KqDWeBywhvexKC3memmDwlHAv9q4Vo2ZK8KtK0CgX7u9J8wXbzdKv-nRnfF_2baTqlYoWUF2h5efl9-n0O6koAMAAA==)):
> [!NOTE] Avoid overusing effects! When you do too much work in them, code often becomes difficult to understand and maintain. See [when not to use effects](#When-not-to-use-effects) to learn about alternative approaches.
Your effects run after the component has been mounted to the DOM, and in a [microtask](https://developer.mozilla.org/en-US/docs/Web/API/HTML_DOM_API/Microtask_guide) after state changes ([demo](/playground/untitled#H4sIAAAAAAAAE31S246bMBD9lZF3pSRSAqTVvrCAVPUP2sdSKY4ZwJJjkD0hSVH-vbINuWxXfQH5zMyZc2ZmZLVUaFn6a2R06ZGlHmBrpvnBvb71fWQHVOSwPbf4GS46TajJspRlVhjZU1HqkhQSWPkHIYdXS5xw-Zas3ueI6FRn7qHFS11_xSRZhIxbFtcDtw7SJb1iXaOg5XIFeQGjzyPRaevYNOGZIJ8qogbpe8CWiy_VzEpTXiQUcvPDkSVrSNZz1UlW1N5eLcqmpdXUvaQ4BmqlhZNUCgxuzFHDqUWNAxrYeUM76AzsnOsdiJbrBp_71lKpn3RRbii-4P3f-IMsRxS-wcDV_bL4PmSdBa2wl7pKnbp8DMgVvJm8ZNskKRkEM_OzyOKQFkgqOYBQ3Nq89Ns0nbIl81vMFN-jKoLMTOr-SOBOJS-Z8f5Y6D1wdcR8dFqvEBdetK-PHwj-z-cH8oHPY54wRJ8Ys7iSQ3Bg3VA9azQbmC9k35kKzYa6PoVtfwbbKVnBixBiGn7Pq0rqJoUtHiCZwAM3jdTPWCVtr_glhVrhecIa3vuksJ_b7TqFs4DPyriSjd5IwoNNQaAmNI-ESfR2p8zimzvN1swdCkvJHPH6-_oX8o1SgcIDAAA=)):
```svelte
<script>
@ -31,11 +32,11 @@ To run _side-effects_ when the component is mounted to the DOM, and when values
<canvas bind:this={canvas} width="100" height="100" />
```
The function passed to `$effect` will run when the component mounts, and will re-run after any changes to the values it reads that were declared with `$state` or `$derived` (including those passed in with `$props`). Re-runs are batched (i.e. changing `color` and `size` in the same moment won't cause two separate runs), and happen after any DOM updates have been applied.
Re-runs are batched (i.e. changing `color` and `size` in the same moment won't cause two separate runs), and happen after any DOM updates have been applied.
You can place `$effect` anywhere, not just at the top level of a component, as long as it is called during component initialization (or while a parent effect is active). It is then tied to the lifecycle of the component (or parent effect) and will therefore destroy itself when the component unmounts (or the parent effect is destroyed).
You can return a function from `$effect`, which will run immediately before the effect re-runs, and before it is destroyed ([demo](/#H4sIAAAAAAAAE42SzW6DMBCEX2Vl5RDaVCQ9JoDUY--9lUox9lKsGBvZC1GEePcaKPnpqSe86_m0M2t6ViqNnu0_e2Z4jWzP3pqGbRhdmrHwHWrCUHvbOjF2Ei-caijLTU4aCYRtDUEKK0-ccL2NDstNrbRWHoU10t8Eu-121gTVCssSBa3XEaQZ9GMrpziGj0p5OAccCgSHwmEgJZwrNNihg6MyhK7j-gii4uYb_YyGUZ5guQwzPdL7b_U4ZNSOvp9T2B3m1rB5cLx4zMkhtc7AHz7YVCVwEFzrgosTBMuNs52SKDegaPbvWnMH8AhUXaNUIY6-hHCldQhUIcyLCFlfAuHvkCKaYk8iYevGGgy2wyyJnpy9oLwG0sjdNe2yhGhJN32HsUzi2xOapNpl_bSLIYnDeeoVLZE1YI3QSpzSfo7-8J5PKbwOmdf2jC6JZyD7HxpPaMk93aHhF6utVKVCyfbkWhy-hh9Z3o_2nQIAAA==)).
You can return a function from `$effect`, which will run immediately before the effect re-runs, and before it is destroyed ([demo](/playground/untitled#H4sIAAAAAAAAE42RQY-bMBCF_8rI2kPopiXpMQtIPfbeW6m0xjyKtWaM7CFphPjvFVB2k2oPe7LmzXzyezOjaqxDVKefo5JrD3VaBLVXrLu5-tb3X-IZTmat0hHv6cazgCWqk8qiCbaXouRSHISMH1gop4coWrA7JE9bp7PO2QjjuY5vA8fDYZ3hUh7QNDCy2yWUFzTOUilpSj9aG-linaMKFGACtKCmSwvGGYGeLQvCWbtnMq3m34grajxHoa1JOUXI93_V_Sfz7Oz7Mafj0ypN-zvHm8dSAmQITP_xaUq2IU1GO1dp80I2Uh_82dao92Rl9R8GvgF0QrbrUFstcFeq0PgAkha0LoICPoeB4w1SJUvsZcj4rvcMlvmvGlGCv6J-DeSgw2vabQnJlm55p7nM0rcTctYei3HZxZSl7XHVqkHEM3k2zpqXfFyj393zU05fpyI6f0HI0hUoPoamC9roKDeo2ivBH1EnCQOmX9NfYw2GHrgCAAA=)).
```svelte
<script>
@ -63,11 +64,11 @@ You can return a function from `$effect`, which will run immediately before the
<button onclick={() => (milliseconds /= 2)}>faster</button>
```
## `$effect` dependencies
### Understanding dependencies
`$effect` automatically picks up any reactivy values (`$state`, `$derived`, `$props`) that are _synchronously_ read inside its function body and registers them as dependencies. When those dependencies change, the `$effect` schedules a rerun.
`$effect` automatically picks up any reactive values (`$state`, `$derived`, `$props`) that are _synchronously_ read inside its function body and registers them as dependencies. When those dependencies change, the `$effect` schedules a rerun.
Values that are read asynchronously — after an `await` or inside a `setTimeout`, for example — will _not_ be tracked. Here, the canvas will be repainted when `color` changes, but not when `size` changes ([demo](/#H4sIAAAAAAAAE31T24rbMBD9lUG7kCxsbG_LvrhOoPQP2r7VhSjy2BbIspHGuTT436tLnMtSCiaOzpw5M2dGPrNaKrQs_3VmmnfIcvZ1GNgro9PgD3aPitCdbT8a4ZHCCiMH2pS6JIUEVv5BWMOzJU64fM9evswR0ave3EKLp7r-jFm2iIwri-s9tx5ywDPWNQpaLl9gvYFz4JHotfVqmvBITi9mJA3St4gtF5-qWZUuvEQo5Oa7F8tewT2XrIOsqL2eWpRNS7eGSkpToFZaOEilwODKjBoOLWrco4FtsLQF0XLdoE2S5LGmm6X6QSflBxKod8IW6afssB8_uAslndJuJNA9hWKw9VO91pmJ92XunHlu_J1nMDk8_p_8q0hvO9NFtA47qavcW12fIzJBmM26ZG9ZVjKIs7ke05hdyT0Ixa11Ad-P6ZUtWbgNheI7VJvYQiH14Bz5a-SYxvtwIqHonqsR12ff8ORkQ-chP70T-L9eGO4HvYAFwRh9UCxS13h0YP2CgmoyG5h3setNhWZF_ZDD23AE2ytZwZMQ4jLYgVeV1I2LYgfZBey4aaR-xCppB8VPOdQKjxes4UMgxcVcvwHf4dzAv9K4ko1eScLO5iDQXQFzL5gl7zdJt-nZnXYfbddXspZYsZzMiNPv6S8Bl41G7wMAAA==)):
Values that are read _asynchronously_ — after an `await` or inside a `setTimeout`, for example — will not be tracked. Here, the canvas will be repainted when `color` changes, but not when `size` changes ([demo](/playground/untitled#H4sIAAAAAAAAE31T246bMBD9lZF3pWSlBEirfaEQqdo_2PatVIpjBrDkGGQPJGnEv1e2IZfVal-wfHzmzJyZ4cIqqdCy9M-F0blDlnqArZjmB3f72XWRHVCRw_bc4me4aDWhJstSlllhZEfbQhekkMDKfwg5PFvihMvX5OXH_CJa1Zrb0-Kpqr5jkiwC48rieuDWQbqgZ6wqFLRcvkC-hYvnkWi1dWqa8ESQTxFRjfQWsOXiWzmr0sSLhEJu3p1YsoJkNUcdZUnN9dagrBu6FVRQHAM10sJRKgUG16bXcGxQ44AGdt7SDkTDdY02iqLHnJVU6hedlWuIp94JW6Tf8oBt_8GdTxlF0b4n0C35ZLBzXb3mmYn3ae6cOW74zj0YVzDNYXRHFt9mprNgHfZSl6mzml8CMoLvTV6wTZIUDEJv5us2iwMtiJRyAKG4tXnhl8O0yhbML0Wm-B7VNlSSSd31BG7z8oIZZ6dgIffAVY_5xdU9Qrz1Bnx8fCfwtZ7v8Qc9j3nB8PqgmMWlHIID6-bkVaPZwDySfWtKNGtquxQ23Qlsq2QJT0KIqb8dL0up6xQ2eIBkAg_c1FI_YqW0neLnFCqFpwmreedJYT7XX8FVOBfwWRhXstZrSXiwKQjUhOZeMIleb5JZfHWn2Yq5pWEpmR7Hv-N_wEqT8hEEAAA=)):
```ts
// @filename: index.ts
@ -139,121 +140,6 @@ $effect(() => {
});
```
## When not to use `$effect`
In general, `$effect` is best considered something of an escape hatch — useful for things like analytics and direct DOM manipulation — rather than a tool you should use frequently. In particular, avoid using it to synchronise state. Instead of this...
```svelte
<script>
let count = $state(0);
let doubled = $state();
// don't do this!
$effect(() => {
doubled = count * 2;
});
</script>
```
...do this:
```svelte
<script>
let count = $state(0);
let doubled = $derived(count * 2);
</script>
```
> [!NOTE] For things that are more complicated than a simple expression like `count * 2`, you can also use `$derived.by`.
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](/#H4sIAAAAAAAACpVRy2rDMBD8lWXJwYE0dg-9KFYg31H3oNirIJBlYa1DjPG_F8l1XEop9LgzOzP7mFAbSwHF-4ROtYQCL97jAXn0sQh3skx4wNANfR2RMtS98XyuXMWWGLhjZUHCa1GcVix4cgwSdoEVU1bsn4wl_Y1I2kS6inekNdWcZXuQZ5giFDWpfwl5WYyT2fynbB1g1UWbTVbm2w6utOpKNq1TGucHhri6rLBX7kYVwtW4RtyVHUhOyXeGVj3klLxnyJP0i8lXNJUx6en-v6A48K85kTimpi0sYj-yAo-Wlh9FcL1LY4K3ahSgLT1OC3ZTXkBxfKN2uVC6T5LjAduuMdpQg4L7geaP-RNHPuClMQIAAA==)):
```svelte
<script>
let total = 100;
let spent = $state(0);
let left = $state(total);
$effect(() => {
left = total - spent;
});
$effect(() => {
spent = total - left;
});
</script>
<label>
<input type="range" bind:value={spent} max={total} />
{spent}/{total} spent
</label>
<label>
<input type="range" bind:value={left} max={total} />
{left}/{total} left
</label>
```
Instead, use callbacks where possible ([demo](/#H4sIAAAAAAAACo2SP2-DMBDFv8rp1CFR84cOXQhU6p6tY-ngwoEsGWPhI0pk8d0rG5yglqGj37v7veMJh7VUZDH9dKhFS5jiuzG4Q74Z_7AXUky4Q9sNfemVzJa9NPxW6IIVMXDHQkEOL0lyipo1pBlyeLIsmDbJ9u4oqhdG2A2mLrgedMmy0zCYSjB9eMaGtuC8WXBkPtOBRd8QHy5CDXSa3Jk7HbOfDgjWuAo_U71kz9vr6Bgc2X44orPjow2dKfFNKhSTSW0GBl9iXmAvdEMFQqDmLgBH6HQYyt3ie0doxTV3IWqEY2DN88eohqePvsf9O9mf_if4HMSVXD89NfEI99qvbMs3RdPv4MXYaSWtUeKWQq3oOlfZCJNCcnildlFgWMcdtl0la0kVptwPNH6NP_uzV0acAgAA)):
```svelte
<script>
let total = 100;
let spent = $state(0);
let left = $state(total);
function updateSpent(e) {
spent = +e.target.value;
left = total - spent;
}
function updateLeft(e) {
left = +e.target.value;
spent = total - left;
}
</script>
<label>
<input type="range" value={spent} oninput={updateSpent} max={total} />
{spent}/{total} spent
</label>
<label>
<input type="range" value={left} oninput={updateLeft} max={total} />
{left}/{total} left
</label>
```
If you need to use bindings, for whatever reason (for example when you want some kind of "writable `$derived`"), consider using getters and setters to synchronise state ([demo](/#H4sIAAAAAAAACo2SQW-DMAyF_4pl7dBqXcsOu1CYtHtvO44dsmKqSCFExFRFiP8-xRCGth52tJ_9PecpA1bakMf0Y0CrasIU35zDHXLvQuGvZJhwh77p2nPoZP7casevhS3YEAM3rAzk8Jwkx9jzjixDDg-eFdMm2S6KoWolyK6ItuCqs2fWjYXOlYrpPTA2tIUhiAVH5iPtWbUX4v1VmY6Okzpzp2OepgNEGu_CT1St2fP2fXQ0juwwHNHZ4ScNmxn1RUaCybR1HUMIMS-wVfZCBYJQ80GAIzRWhvJh9d4RanXLB7Ea4SCsef4Qu1IG68Xu387h9D_GJ2ne8ZXpxTZUv1w994amjxCaMc1Se2dUn0Jl6DaHeFEuhWT_QvUqOlnHHdZNqStNJabcdjR-jt8IbC-7lgIAAA==)):
```svelte
<script>
let total = 100;
let spent = $state(0);
let left = {
get value() {
return total - spent;
},
set value(v) {
spent = total - v;
}
};
</script>
<label>
<input type="range" bind:value={spent} max={total} />
{spent}/{total} spent
</label>
<label>
<input type="range" bind:value={left.value} max={total} />
{left.value}/{total} left
</label>
```
If you absolutely have to update `$state` within an effect and run into an infinite loop because you read and write to the same `$state`, use [untrack](svelte#untrack).
## `$effect.pre`
In rare cases, you may need to run code _before_ the DOM updates. For this we can use the `$effect.pre` rune:
@ -289,7 +175,7 @@ In rare cases, you may need to run code _before_ the DOM updates. For this we ca
</div>
```
Apart from the timing, `$effect.pre` works exactly like `$effect` — refer to its documentation for more info.
Apart from the timing, `$effect.pre` works exactly like `$effect`.
## `$effect.tracking`
@ -375,3 +261,118 @@ nested effects that you want to manually control. This rune also allows for crea
});
</script>
```
## When not to use effects
In general, `$effect` is best considered something of an escape hatch — useful for things like analytics and direct DOM manipulation — rather than a tool you should use frequently. In particular, avoid using it to synchronise state. Instead of this...
```svelte
<script>
let count = $state(0);
let doubled = $state();
// don't do this!
$effect(() => {
doubled = count * 2;
});
</script>
```
...do this:
```svelte
<script>
let count = $state(0);
let doubled = $derived(count * 2);
</script>
```
> [!NOTE] For things that are more complicated than a simple expression like `count * 2`, you can also use `$derived.by`.
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](/#H4sIAAAAAAAACpVRy2rDMBD8lWXJwYE0dg-9KFYg31H3oNirIJBlYa1DjPG_F8l1XEop9LgzOzP7mFAbSwHF-4ROtYQCL97jAXn0sQh3skx4wNANfR2RMtS98XyuXMWWGLhjZUHCa1GcVix4cgwSdoEVU1bsn4wl_Y1I2kS6inekNdWcZXuQZ5giFDWpfwl5WYyT2fynbB1g1UWbTVbm2w6utOpKNq1TGucHhri6rLBX7kYVwtW4RtyVHUhOyXeGVj3klLxnyJP0i8lXNJUx6en-v6A48K85kTimpi0sYj-yAo-Wlh9FcL1LY4K3ahSgLT1OC3ZTXkBxfKN2uVC6T5LjAduuMdpQg4L7geaP-RNHPuClMQIAAA==)):
```svelte
<script>
let total = 100;
let spent = $state(0);
let left = $state(total);
$effect(() => {
left = total - spent;
});
$effect(() => {
spent = total - left;
});
</script>
<label>
<input type="range" bind:value={spent} max={total} />
{spent}/{total} spent
</label>
<label>
<input type="range" bind:value={left} max={total} />
{left}/{total} left
</label>
```
Instead, use callbacks where possible ([demo](/#H4sIAAAAAAAACo2SP2-DMBDFv8rp1CFR84cOXQhU6p6tY-ngwoEsGWPhI0pk8d0rG5yglqGj37v7veMJh7VUZDH9dKhFS5jiuzG4Q74Z_7AXUky4Q9sNfemVzJa9NPxW6IIVMXDHQkEOL0lyipo1pBlyeLIsmDbJ9u4oqhdG2A2mLrgedMmy0zCYSjB9eMaGtuC8WXBkPtOBRd8QHy5CDXSa3Jk7HbOfDgjWuAo_U71kz9vr6Bgc2X44orPjow2dKfFNKhSTSW0GBl9iXmAvdEMFQqDmLgBH6HQYyt3ie0doxTV3IWqEY2DN88eohqePvsf9O9mf_if4HMSVXD89NfEI99qvbMs3RdPv4MXYaSWtUeKWQq3oOlfZCJNCcnildlFgWMcdtl0la0kVptwPNH6NP_uzV0acAgAA)):
```svelte
<script>
let total = 100;
let spent = $state(0);
let left = $state(total);
function updateSpent(e) {
spent = +e.target.value;
left = total - spent;
}
function updateLeft(e) {
left = +e.target.value;
spent = total - left;
}
</script>
<label>
<input type="range" value={spent} oninput={updateSpent} max={total} />
{spent}/{total} spent
</label>
<label>
<input type="range" value={left} oninput={updateLeft} max={total} />
{left}/{total} left
</label>
```
If you need to use bindings, for whatever reason (for example when you want some kind of "writable `$derived`"), consider using getters and setters to synchronise state ([demo](/#H4sIAAAAAAAACo2SQW-DMAyF_4pl7dBqXcsOu1CYtHtvO44dsmKqSCFExFRFiP8-xRCGth52tJ_9PecpA1bakMf0Y0CrasIU35zDHXLvQuGvZJhwh77p2nPoZP7casevhS3YEAM3rAzk8Jwkx9jzjixDDg-eFdMm2S6KoWolyK6ItuCqs2fWjYXOlYrpPTA2tIUhiAVH5iPtWbUX4v1VmY6Okzpzp2OepgNEGu_CT1St2fP2fXQ0juwwHNHZ4ScNmxn1RUaCybR1HUMIMS-wVfZCBYJQ80GAIzRWhvJh9d4RanXLB7Ea4SCsef4Qu1IG68Xu387h9D_GJ2ne8ZXpxTZUv1w994amjxCaMc1Se2dUn0Jl6DaHeFEuhWT_QvUqOlnHHdZNqStNJabcdjR-jt8IbC-7lgIAAA==)):
```svelte
<script>
let total = 100;
let spent = $state(0);
let left = {
get value() {
return total - spent;
},
set value(v) {
spent = total - v;
}
};
</script>
<label>
<input type="range" bind:value={spent} max={total} />
{spent}/{total} spent
</label>
<label>
<input type="range" bind:value={left.value} max={total} />
{left.value}/{total} left
</label>
```
If you absolutely have to update `$state` within an effect and run into an infinite loop because you read and write to the same `$state`, use [untrack](svelte#untrack).

@ -0,0 +1,128 @@
---
title: $props
---
The inputs to a component are referred to as _props_, which is short for _properties_. You pass props to components just like you pass attributes to elements:
```svelte
<script>
import MyComponent from './MyComponent.svelte';
</script>
/// file: App.svelte
<MyComponent adjective="cool" />
```
On the other side, inside `MyComponent.svelte`, we can receive props with the `$props` rune...
```svelte
<script>
let props = $props();
</script>
/// file: MyComponent.svelte
<p>this component is {props.adjective}</p>
```
...though more commonly, you'll [_destructure_](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment) your props:
```svelte
/// file: MyComponent.svelte
<script>
let +++{ adjective }+++ = $props();
</script>
<p>this component is {+++adjective+++}</p>
```
## Fallback values
Destructuring allows us to declare fallback values, which are used if the parent component does not set a given prop:
```js
/// file: MyComponent.svelte
let { adjective = 'happy' } = $props();
```
> [!NOTE] Fallback values are not turned into reactive state proxies.
## Renaming props
We can also use the destructuring assignment to rename props, which is necessary if they're invalid identifiers, or a JavaScript keyword like `super`:
```js
let { super: trouper = 'lights are gonna find me' } = $props();
```
## Rest props
Finally, we can use a _rest property_ to get, well, the rest of the props:
```js
let { a, b, c, ...others } = $props();
```
## Updating props
References to a prop inside a component update when the prop itself updates — when `count` changes in `App.svelte`, it will also change inside `Child.svelte`. But the child component is able to temporarily override the prop value, which can be useful for unsaved emphemeral state ([demo](/playground/untitled#H4sIAAAAAAAAE6WQ0WrDMAxFf0WIQR0Wmu3VTQJln7HsIfVcZubIxlbGRvC_DzuBraN92qPula50tODZWB1RPi_IX16jLALWSOOUq6P3-_ihLWftNEZ9TVeOWBNHlNhGFYznfqCBzeRdYHh6M_YVzsFNsNs3pdpGd4eBcqPVDMrNxNDBXeSRtXioDgO1zU8ataeZ2RE4Utao924RFXQ9iHXwvoPHKpW1xY4g_Bg0cSVhKS0p560Za95612ZC02ONrD8ZJYdZp_rGQ37ff_mSP86Np2TWZaNNmdcH56P4P67K66_SXoK9pG-5dF5Z9QEAAA==)):
<!-- prettier-ignore -->
```svelte
/// file: App.svelte
<script>
import Child from './Child.svelte';
let count = $state(0);
</script>
<button onclick={() => (count += 1)}>
clicks (parent): {count}
</button>
<Child {count} />
```
<!-- prettier-ignore -->
```svelte
/// file: Child.svelte
<script>
let { count } = $props();
</script>
<button onclick={() => (count += 1)}>
clicks (child): {count}
</button>
```
## Type safety
You can add type safety to your components by annotating your props, as you would with any other variable declaration. In TypeScript that might look like this...
```svelte
<script lang="ts">
let { adjective }: { adjective: string } = $props();
</script>
```
...while in JSDoc you can do this:
```svelte
<script>
/** @type {{ adjective: string }} */
let { adjective } = $props();
</script>
```
You can, of course, separate the type declaration from the annotation:
```svelte
<script lang="ts">
interface Props {
adjective: string;
}
let { adjective }: Props = $props();
</script>
```
Adding types is recommended, as it ensures that people using your component can easily discover which props they should provide.

@ -0,0 +1,54 @@
---
title: $bindable
---
Ordinarily, props go one way, from parent to child. This makes it easy to understand how data flows around your app.
In Svelte, component props can be _bound_, which means that data can also flow _up_ from child to parent. This isn't something you should do often, but it can simplify your code if used sparingly and carefully.
It also means that a state proxy can be _mutated_ in the child.
> [!NOTE] Mutation is also possible with normal props, but is strongly discouraged — Svelte will warn you if it detects that a component is mutating state it does not 'own'.
To mark a prop as bindable, we use the `$bindable` rune:
<!-- prettier-ignore -->
```svelte
/// file: FancyInput.svelte
<script>
let { value = $bindable(), ...props } = $props();
</script>
<input bind:value={value} {...props} />
<style>
input {
font-family: 'Comic Sans MS';
color: deeppink;
}
</style>
```
Now, a component that uses `<FancyInput>` can add the [`bind:`](bind) directive ([demo](/playground/untitled#H4sIAAAAAAAAE3WQwWrDMBBEf2URBSfg2nfFMZRCoYeecqx6UJx1IyqvhLUONcb_XqSkTUOSk1az7DBvJtEai0HI90nw6FHIJIhckO7i78n7IhzQctS2OuAtvXHESByEFFVoeuO5VqTYdN71DC-amvGV_MDQ9q6DrCjP0skkWymKJxYZOgxBfyKs4SGwZlxke7TWZcuVoqo8-1P1z3lraCcP2g64nk4GM5S1osrXf0JV-lrkgvGbheR-wDm_g30V8JL-1vpOCZFogpQsEsWcemtxscyhKArfOx9gjps0Lq4hzRVfemaYfu-PoIqqwKPFY_XpaIqj4tYRP7a6M3aUkD27zjSw0RTgbZN6Z8WNs66XsEP03tBXUueUJFlelvYx_wCuI3leNwIAAA==)):
<!-- prettier-ignore -->
```svelte
/// App.svelte
<script>
import FancyInput from './FancyInput.svelte';
let message = $state('hello');
</script>
<FancyInput bind:value={message} />
<p>{message}</p>
```
The parent component doesn't _have_ to use `bind:` — it can just pass a normal prop. Some parents don't want to listen to what their children have to say.
In this case, you can specify a fallback value for when no prop is passed at all:
```js
/// file: FancyInput.svelte
let { value = $bindable('fallback'), ...props } = $props();
```

@ -0,0 +1,44 @@
---
title: $inspect
---
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](/#H4sIAAAAAAAACkWQ0YqDQAxFfyUMhSotdZ-tCvu431AXtGOqQ2NmmMm0LOK_r7Utfby5JzeXTOpiCIPKT5PidkSVq2_n1F7Jn3uIcEMSXHSw0evHpAjaGydVzbUQCmgbWaCETZBWMPlKj29nxBDaHj_edkAiu12JhdkYDg61JGvE_s2nR8gyuBuiJZuDJTyQ7eE-IEOzog1YD80Lb0APLfdYc5F9qnFxjiKWwbImo6_llKRQVs-2u91c_bD2OCJLkT3JZasw7KLA2XCX31qKWE6vIzNk1fKE0XbmYrBTufiI8-_8D2cUWBA_AQAA)):
```svelte
<script>
let count = $state(0);
let message = $state('hello');
$inspect(count, message); // will console.log when `count` or `message` change
</script>
<button onclick={() => count++}>Increment</button>
<input bind:value={message} />
```
## $inspect(...).with
`$inspect` returns a property `with`, which you can invoke with a callback, which will then be invoked instead of `console.log`. The first argument to the callback is either `"init"` or `"update"`; subsequent arguments are the values passed to `$inspect` ([demo](/#H4sIAAAAAAAACkVQ24qDMBD9lSEUqlTqPlsj7ON-w7pQG8c2VCchmVSK-O-bKMs-DefKYRYx6BG9qL4XQd2EohKf1opC8Nsm4F84MkbsTXAqMbVXTltuWmp5RAZlAjFIOHjuGLOP_BKVqB00eYuKs82Qn2fNjyxLtcWeyUE2sCRry3qATQIpJRyD7WPVMf9TW-7xFu53dBcoSzAOrsqQNyOe2XUKr0Xi5kcMvdDB2wSYO-I9vKazplV1-T-d6ltgNgSG1KjVUy7ZtmdbdjqtzRcphxMS1-XubOITJtPrQWMvKnYB15_1F7KKadA_AQAA)):
```svelte
<script>
let count = $state(0);
$inspect(count).with((type, count) => {
if (type === 'update') {
debugger; // or `console.trace`, or whatever you want
}
});
</script>
<button onclick={() => count++}>Increment</button>
```
A convenient way to find the origin of some change is to pass `console.trace` to `with`:
```js
// @errors: 2304
$inspect(stuff).with(console.trace);
```
> [!NOTE] `$inspect` only works during development. In a production build it becomes a noop.

@ -0,0 +1,37 @@
---
title: $host
---
When compiling a component as a custom element, the `$host` rune provides access to the host element, allowing you to (for example) dispatch custom events ([demo](/playground/untitled#H4sIAAAAAAAAE41Ry2rDMBD8FSECtqkTt1fHFpSSL-ix7sFRNkTEXglrnTYY_3uRlDgxTaEHIfYxs7szA9-rBizPPwZOZwM89wmecqxbF70as7InaMjltrWFR3mpkQDJ8pwXVnbKkKiwItUa3RGLVtk7gTHQXRDR2lXda4CY1D0SK9nCUk0QPyfrCovsRoNFe17aQOAwGncgO2gBqRzihJXiQrEs2csYOhQ-7HgKHaLIbpRhhBG-I2eD_8ciM4KnnOCbeE5dD2P6h0Dz0-Yi_arNhPLJXBtSGi2TvSXdbpqwdsXvjuYsC1veabvvUTog2ylrapKH2G2XsMFLS4uDthQnq2t1cwKkGOGLvYU5PvaQxLsxOkPmsm97Io1Mo2yUPF6VnOZFkw1RMoopKLKAE_9gmGxyDFMwMcwN-Bx_ABXQWmOtAgAA)):
<!-- prettier-ignore -->
```svelte
/// file: Stepper.svelte
<svelte:options customElement="my-stepper" />
<script>
function dispatch(type) {
+++$host()+++.dispatchEvent(new CustomEvent(type));
}
</script>
<button onclick={() => dispatch('decrement')}>decrement</button>
<button onclick={() => dispatch('increment')}>increment</button>
```
<!-- prettier-ignore -->
```svelte
/// file: App.svelte
<script>
import './Stepper.svelte';
let count = $state(0);
</script>
<my-stepper
ondecrement={() => count -= 1}
onincrement={() => count += 1}
></my-stepper>
<p>count: {count}</p>
```

@ -1,201 +0,0 @@
---
title: State
---
Svelte 5 uses _runes_, a powerful set of primitives for controlling reactivity inside your Svelte components and inside `.svelte.js` and `.svelte.ts` modules.
Runes are function-like symbols that provide instructions to the Svelte compiler. You don't need to import them from anywhere — when you use Svelte, they're part of the language. This page describes the runes that are concerned with managing state in your application.
## `$state`
The `$state` rune is the at the heart of the runes API. It is used to declare reactive state:
```svelte
<script>
let count = $state(0);
</script>
<button onclick={() => count++}>
clicks: {count}
</button>
```
Variables declared with `$state` are the variable _itself_, in other words there's no wrapper around the value that it contains. This is possible thanks to the compiler-nature of Svelte. As such, updating state is done through simple reassignment.
You can also use `$state` in class fields (whether public or private):
```js
// @errors: 7006 2554
class Todo {
done = $state(false);
text = $state();
constructor(text) {
this.text = text;
}
reset() {
this.text = '';
this.done = false;
}
}
```
> [!NOTE] In this example, the compiler transforms `done` and `text` into `get`/`set` methods on the class prototype referencing private fields
Objects and arrays are made deeply reactive by wrapping them with [`Proxies`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy). What that means is that in the following example, we can mutate the `entries` object and the UI will still update - but only the list item that is actually changed will rerender:
```svelte
<script>
let entries = $state([
{ id: 1, text: 'foo' },
{ id: 2, text: 'bar' }
]);
</script>
{#each entries as entry (entry.id)}
{entry.text}
{/each}
<button onclick={() => (entries[1].text = 'baz')}>change second entry text</button>
```
> [!NOTE] Only POJOs (plain old JavaScript objects) are made deeply reactive. Reactivity will stop at class boundaries and leave those alone
## `$state.raw`
State declared with `$state.raw` cannot be mutated; it can only be _reassigned_. In other words, rather than assigning to a property of an object, or using an array method like `push`, replace the object or array altogether if you'd like to update it:
```js
let person = $state.raw({
name: 'Heraclitus',
age: 49
});
// this will have no effect (and will throw an error in dev)
person.age += 1;
// this will work, because we're creating a new person
person = {
name: 'Heraclitus',
age: 50
};
```
This can improve performance with large arrays and objects that you weren't planning to mutate anyway, since it avoids the cost of making them reactive. Note that raw state can _contain_ reactive state (for example, a raw array of reactive objects).
## `$state.snapshot`
To take a static snapshot of a deeply reactive `$state` proxy, use `$state.snapshot`:
```svelte
<script>
let counter = $state({ count: 0 });
function onclick() {
// Will log `{ count: ... }` rather than `Proxy { ... }`
console.log($state.snapshot(counter));
}
</script>
```
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`.
## `$derived`
Derived state is declared with the `$derived` rune:
```svelte
<script>
let count = $state(0);
let doubled = $derived(count * 2);
</script>
<button onclick={() => count++}>
{doubled}
</button>
<p>{count} doubled is {doubled}</p>
```
The expression inside `$derived(...)` should be free of side-effects. Svelte will disallow state changes (e.g. `count++`) inside derived expressions.
As with `$state`, you can mark class fields as `$derived`.
## `$derived.by`
Sometimes you need to create complex derivations that don't fit inside a short expression. In these cases, you can use `$derived.by` which accepts a function as its argument.
```svelte
<script>
let numbers = $state([1, 2, 3]);
let total = $derived.by(() => {
let total = 0;
for (const n of numbers) {
total += n;
}
return total;
});
</script>
<button onclick={() => numbers.push(numbers.length + 1)}>
{numbers.join(' + ')} = {total}
</button>
```
In essence, `$derived(expression)` is equivalent to `$derived.by(() => expression)`.
## Universal reactivity
In the examples above, `$state` and `$derived` only appear at the top level of components. You can also use them within functions or even outside Svelte components inside `.svelte.js` or `.svelte.ts` modules.
```ts
/// file: counter.svelte.ts
export function createCounter(initial: number) {
let count = $state(initial);
let double = $derived(count * 2);
return {
get count() {
return count;
},
get double() {
return double;
},
increment: () => count++
};
}
```
```svelte
<!--- file: App.svelte --->
<script>
import { createCounter } from './counter.svelte';
const counter = createCounter();
</script>
<button onclick={counter.increment}>{counter.count} / {counter.double}</button>
```
There are a few things to note in the above example:
- We're using getters to transport reactivity across the function boundary. This way we keep reactivity "alive". If we were to return the value itself, it would be fixed to the value at that point in time. This is no different to how regular JavaScript variables behave.
- We're not destructuring the counter at the usage site. Because we're using getters, destructuring would fix `count` and `double` to the value at that point in time. To keep the getters "alive", we're not using destructuring. Again, this is how regular JavaScript works.
If you have shared state you want to manipulate from various places, you don't need to resort to getters. Instead, you can take advantage of `$state` being deeply reactive and only update its properties, not the value itself:
```ts
/// file: app-state.svelte.ts
export const appState = $state({
loggedIn: true
});
```
```svelte
<!--- file: App.svelte --->
<script>
import { appState } from './app-state.svelte';
</script>
<button onclick={() => (appState.loggedIn = false)}>Log out</button>
```

@ -2,11 +2,11 @@
title: Basic markup
---
- [basically what we have in the Svelte docs today](https://svelte.dev/docs/basic-markup)
Markup inside a Svelte component can be thought of as HTML++.
## Tags
A lowercase tag, like `<div>`, denotes a regular HTML element. A capitalised tag, such as `<Widget>` or `<Namespace.Widget>`, indicates a _component_.
A lowercase tag, like `<div>`, denotes a regular HTML element. A capitalised tag or a tag that uses dot notation, such as `<Widget>` or `<my.stuff>`, indicates a _component_.
```svelte
<script>
@ -56,12 +56,12 @@ All other attributes are included unless their value is [nullish](https://develo
<div title={null}>This div has no title attribute</div>
```
Quoting a singular expression does not affect how the value is parsed yet, but in Svelte 6 it will:
<!-- prettier-ignore -->
```svelte
<button disabled="{number !== 42}">...</button>
```
> [!NOTE] Quoting a singular expression does not affect how the value is parsed, but in Svelte 6 it will cause the value to be coerced to a string:
>
> <!-- prettier-ignore -->
> ```svelte
> <button disabled="{number !== 42}">...</button>
> ```
When the attribute name and value match (`name={name}`), they can be replaced with `{name}`.
@ -88,12 +88,6 @@ An element or component can have multiple spread attributes, interspersed with r
<Widget {...things} />
```
> [!NOTE] The `value` attribute of an `input` element or its children `option` elements must not be set with spread attributes when using `bind:group` or `bind:checked`. Svelte needs to be able to see the element's `value` directly in the markup in these cases so that it can link it to the bound variable.
> [!NOTE] Sometimes, the attribute order matters as Svelte sets attributes sequentially in JavaScript. For example, `<input type="range" min="0" max="1" value={0.5} step="0.1"/>`, Svelte will attempt to set the value to `1` (rounding up from 0.5 as the step by default is 1), and then set the step to `0.1`. To fix this, change it to `<input type="range" min="0" max="1" step="0.1" value={0.5}/>`.
> [!NOTE] Another example is `<img src="..." loading="lazy" />`. Svelte will set the img `src` before making the img element `loading="lazy"`, which is probably too late. Change this to `<img loading="lazy" src="...">` to make the image lazily loaded.
## Events
Listening to DOM events is possible by adding attributes to the element that start with `on`. For example, to listen to the `click` event, add the `onclick` attribute to a button:
@ -108,7 +102,6 @@ Because events are just attributes, the same rules as for attributes apply:
- you can use the shorthand form: `<button {onclick}>click me</button>`
- you can spread them: `<button {...thisSpreadContainsEventAttributes}>click me</button>`
- component events are just (callback) properties and don't need a separate concept
Timing-wise, event attributes always fire after events from bindings (e.g. `oninput` always fires after an update to `bind:value`). Under the hood, some event handlers are attached directly with `addEventListener`, while others are _delegated_.

@ -0,0 +1,40 @@
---
title: {#if ...}
---
```svelte
<!--- copy: false --->
{#if expression}...{/if}
```
```svelte
<!--- copy: false --->
{#if expression}...{:else if expression}...{/if}
```
```svelte
<!--- copy: false --->
{#if expression}...{:else}...{/if}
```
Content that is conditionally rendered can be wrapped in an if block.
```svelte
{#if answer === 42}
<p>what was the question?</p>
{/if}
```
Additional conditions can be added with `{:else if expression}`, optionally ending in an `{:else}` clause.
```svelte
{#if porridge.temperature > 100}
<p>too hot!</p>
{:else if 80 > porridge.temperature}
<p>too cold!</p>
{:else}
<p>just right!</p>
{/if}
```
(Blocks don't have to wrap elements, they can also wrap text within elements.)

@ -0,0 +1,92 @@
---
title: {#each ...}
---
```svelte
<!--- copy: false --->
{#each expression as name}...{/each}
```
```svelte
<!--- copy: false --->
{#each expression as name, index}...{/each}
```
Iterating over values can be done with an each block. The values in question can be arrays, array-like objects (i.e. anything with a `length` property), or iterables like `Map` and `Set` — in other words, anything that can be used with `Array.from`.
```svelte
<h1>Shopping list</h1>
<ul>
{#each items as item}
<li>{item.name} x {item.qty}</li>
{/each}
</ul>
```
You can use each blocks to iterate over any array or array-like value — that is, any object with a `length` property.
An each block can also specify an _index_, equivalent to the second argument in an `array.map(...)` callback:
```svelte
{#each items as item, i}
<li>{i + 1}: {item.name} x {item.qty}</li>
{/each}
```
## Keyed each blocks
```svelte
<!--- copy: false --->
{#each expression as name (key)}...{/each}
```
```svelte
<!--- copy: false --->
{#each expression as name, index (key)}...{/each}
```
If a _key_ expression is provided — which must uniquely identify each list item — Svelte will use it to diff the list when data changes, rather than adding or removing items at the end. The key can be any object, but strings and numbers are recommended since they allow identity to persist when the objects themselves change.
```svelte
{#each items as item (item.id)}
<li>{item.name} x {item.qty}</li>
{/each}
<!-- or with additional index value -->
{#each items as item, i (item.id)}
<li>{i + 1}: {item.name} x {item.qty}</li>
{/each}
```
You can freely use destructuring and rest patterns in each blocks.
```svelte
{#each items as { id, name, qty }, i (id)}
<li>{i + 1}: {name} x {qty}</li>
{/each}
{#each objects as { id, ...rest }}
<li><span>{id}</span><MyComponent {...rest} /></li>
{/each}
{#each items as [id, ...rest]}
<li><span>{id}</span><MyComponent values={rest} /></li>
{/each}
```
## Else blocks
```svelte
<!--- copy: false --->
{#each expression as name}...{:else}...{/each}
```
An each block can also have an `{:else}` clause, which is rendered if the list is empty.
```svelte
{#each todos as todo}
<p>{todo.text}</p>
{:else}
<p>No tasks today!</p>
{/each}
```

@ -0,0 +1,24 @@
---
title: {#key ...}
---
```svelte
<!--- copy: false --->
{#key expression}...{/key}
```
Key blocks destroy and recreate their contents when the value of an expression changes. When used around components, this will cause them to be reinstantiated and reinitialised:
```svelte
{#key value}
<Component />
{/key}
```
It's also useful if you want a transition to play whenever a value changes:
```svelte
{#key value}
<div transition:fade>{value}</div>
{/key}
```

@ -1,20 +1,7 @@
---
title: Data fetching
title: {#await ...}
---
Fetching data is a fundamental part of apps interacting with the outside world. Svelte is unopinionated with how you fetch your data. The simplest way would be using the built-in `fetch` method:
```svelte
<script>
let response = $state();
fetch('/api/data').then(async (r) => (response = r.json()));
</script>
```
While this works, it makes working with promises somewhat unergonomic. Svelte alleviates this problem using the `#await` block.
## {#await ...}
```svelte
<!--- copy: false --->
{#await expression}...{:then name}...{:catch name}...{/await}
@ -35,9 +22,7 @@ While this works, it makes working with promises somewhat unergonomic. Svelte al
{#await expression catch name}...{/await}
```
Await blocks allow you to branch on the three possible states of a Promise — pending, fulfilled or rejected.
In SSR mode, only the pending branch will be rendered on the server.
If the provided expression is not a Promise only the fulfilled branch will be rendered, including in SSR mode.
Await blocks allow you to branch on the three possible states of a [`Promise`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) — pending, fulfilled or rejected.
```svelte
{#await promise}
@ -52,6 +37,10 @@ If the provided expression is not a Promise only the fulfilled branch will be re
{/await}
```
> [!NOTE] During server-side rendering, only the pending branch will be rendered.
>
> If the provided expression is not a `Promise` only the `:then` branch will be rendered, including during server-side rendering.
The `catch` block can be omitted if you don't need to render anything when the promise rejects (or no error is possible).
```svelte
@ -79,7 +68,3 @@ Similarly, if you only want to show the error state, you can omit the `then` blo
<p>The error is {error}</p>
{/await}
```
## SvelteKit loaders
Fetching inside your components is great for simple use cases, but it's prone to data loading waterfalls and makes code harder to work with because of the promise handling. SvelteKit solves this problem by providing a opinionated data loading story that is coupled to its router. Learn more about it [in the docs](../kit).

@ -1,15 +1,18 @@
---
title: Snippets
title: {#snippet ...}
---
Better title needed?
```svelte
<!--- copy: false --->
{#snippet name()}...{/if}
```
- `#snippet`
- `@render`
- how they can be used to reuse markup
- how they can be used to pass UI content to components
```svelte
<!--- copy: false --->
{#snippet name(param1, param2, paramN)}...{/if}
```
Snippets, and _render tags_, are a way to create reusable chunks of markup inside your components. Instead of writing duplicative code like [this](/#H4sIAAAAAAAAE5VUYW-kIBD9K8Tmsm2yXXRzvQ-s3eR-R-0HqqOQKhAZb9sz_vdDkV1t000vRmHewMx7w2AflbIGG7GnPlK8gYhFv42JthG-m9Gwf6BGcLbVXZuPSGrzVho8ZirDGpDIhldgySN5GpEMez9kaNuckY1ANJZRamRuu2ZnhEZt6a84pvs43mzD4pMsUDDi8DMkQFYCGdkvsJwblFq5uCik9bmJ4JZwUkv1eoknWigX2eGNN6aGXa6bjV8ybP-X7sM36T58SVcrIIV2xVIaA41xeD5kKqWXuqpUJEefOqVuOkL9DfBchGrzWfu0vb-RpTd3o-zBR045Ga3HfuE5BmJpKauuhbPtENlUF2sqR9jqpsPSxWsMrlngyj3VJiyYjJXb1-lMa7IWC-iSk2M5Zzh-SJjShe-siq5kpZRPs55BbSGU5YPyte4vVV_VfFXxVb10dSLf17pS2lM5HnpPxw4Zpv6x-F57p0jI3OKlVnhv5V9wPQrNYQQ9D_f6aGHlC89fq1Z3qmDkJCTCweOGF4VUFSPJvD_DhreVdA0eu8ehJJ5x91dBaBkpWm3ureCFPt3uzRv56d4kdp-2euG38XZ6dsnd3ZmPG9yRBCrzRUvi-MccOdwz3qE-fOZ7AwAhlrtTUx3c76vRhSwlFBHDtoPhefgHX3dM0PkEAAA=)...
Snippets, and [render tags](@render), are a way to create reusable chunks of markup inside your components. Instead of writing duplicative code like [this](/#H4sIAAAAAAAAE5VUYW-kIBD9K8Tmsm2yXXRzvQ-s3eR-R-0HqqOQKhAZb9sz_vdDkV1t000vRmHewMx7w2AflbIGG7GnPlK8gYhFv42JthG-m9Gwf6BGcLbVXZuPSGrzVho8ZirDGpDIhldgySN5GpEMez9kaNuckY1ANJZRamRuu2ZnhEZt6a84pvs43mzD4pMsUDDi8DMkQFYCGdkvsJwblFq5uCik9bmJ4JZwUkv1eoknWigX2eGNN6aGXa6bjV8ybP-X7sM36T58SVcrIIV2xVIaA41xeD5kKqWXuqpUJEefOqVuOkL9DfBchGrzWfu0vb-RpTd3o-zBR045Ga3HfuE5BmJpKauuhbPtENlUF2sqR9jqpsPSxWsMrlngyj3VJiyYjJXb1-lMa7IWC-iSk2M5Zzh-SJjShe-siq5kpZRPs55BbSGU5YPyte4vVV_VfFXxVb10dSLf17pS2lM5HnpPxw4Zpv6x-F57p0jI3OKlVnhv5V9wPQrNYQQ9D_f6aGHlC89fq1Z3qmDkJCTCweOGF4VUFSPJvD_DhreVdA0eu8ehJJ5x91dBaBkpWm3ureCFPt3uzRv56d4kdp-2euG38XZ6dsnd3ZmPG9yRBCrzRUvi-MccOdwz3qE-fOZ7AwAhlrtTUx3c76vRhSwlFBHDtoPhefgHX3dM0PkEAAA=)...
```svelte
{#each images as image}
@ -34,12 +37,7 @@ Snippets, and _render tags_, are a way to create reusable chunks of markup insid
```svelte
{#snippet figure(image)}
<figure>
<img
src={image.src}
alt={image.caption}
width={image.width}
height={image.height}
/>
<img src={image.src} alt={image.caption} width={image.width} height={image.height} />
<figcaption>{image.caption}</figcaption>
</figure>
{/snippet}
@ -248,6 +246,10 @@ We can tighten things up further by declaring a generic, so that `data` and `row
</script>
```
## Programmatic snippets
Snippets can be created programmatically with the [`createRawSnippet`](svelte#createRawSnippet) API. This is intended for advanced use cases.
## Snippets and slots
In Svelte 4, content can be passed to components using [slots](https://svelte.dev/docs/special-elements#slot). Snippets are more powerful and flexible, and as such slots are deprecated in Svelte 5.

@ -0,0 +1,39 @@
---
title: {@render ...}
---
To render a [snippet](snippet), use a `{@render ...}` tag.
```svelte
{#snippet sum(a, b)}
<p>{a} + {b} = {a + b}</p>
{/snippet}
{@render sum(1, 2)}
{@render sum(3, 4)}
{@render sum(5, 6)}
```
The expression can be an identifer like `sum`, or an arbitrary JavaScript expression:
```svelte
{@render (cool ? coolSnippet : lameSnippet)()}
```
## Optional snippets
If the snippet is potentially undefined — for example, because it's an incoming prop — then you can use optional chaining to only render it when it _is_ defined:
```svelte
{@render children?.()}
```
Alternatively, use an [`{#if ...}`](if) block with an `:else` clause to render fallback content:
```svelte
{#if children}
{@render children()}
{:else}
<p>fallback content</p>
{/if}
```

@ -0,0 +1,51 @@
---
title: {@html ...}
---
To inject raw HTML into your component, use the `{@html ...}` tag:
```svelte
<article>
{@html content}
</article>
```
> [!NOTE] Make sure that you either escape the passed string or only populate it with values that are under your control in order to prevent [XSS attacks](https://owasp.org/www-community/attacks/xss/). Never render unsanitized content.
The expression should be valid standalone HTML — this will not work, because `</div>` is not valid HTML:
```svelte
{@html '<div>'}content{@html '</div>'}
```
It also will not compile Svelte code.
## Styling
Content rendered this way is 'invisible' to Svelte and as such will not receive [scoped styles](styles-and-classes) — in other words, this will not work, and the `a` and `img` styles will be regarded as unused:
<!-- prettier-ignore -->
```svelte
<article>
{@html content}
</article>
<style>
article {
a { color: hotpink }
img { width: 100% }
}
</style>
```
Instead, use the `:global` modifier to target everything inside the `<article>`:
<!-- prettier-ignore -->
```svelte
<style>
article +++:global+++ {
a { color: hotpink }
img { width: 100% }
}
</style>
```

@ -0,0 +1,14 @@
---
title: {@const ...}
---
The `{@const ...}` tag defines a local constant.
```svelte
{#each boxes as box}
{@const area = box.width * box.height}
{box.width} * {box.height} = {area}
{/each}
```
`{@const}` is only allowed as an immediate child of a block — `{#if ...}`, `{#each ...}`, `{#snippet ...}` and so on — or a `<Component />`.

@ -1,47 +1,97 @@
---
title: Bindings
title: bind:
---
- how for dom elements
- list of all bindings
- how for components
Data ordinarily flows down, from parent to child. The `bind:` directive allows data to flow the other way, from child to parent.
Most of the time a clear separation between data flowing down and events going up is worthwhile and results in more robust apps. But in some cases - especially when interacting with form elements - it's more ergonomic to declare a two way binding. Svelte provides many element bindings out of the box, and also allows component bindings.
## bind:_property_ for elements
The general syntax is `bind:property={expression}`, where `expression` is an _lvalue_ (i.e. a variable or an object property). When the expression is an identifier with the same name as the property, we can omit the expression — in other words these are equivalent:
<!-- prettier-ignore -->
```svelte
<!--- copy: false --->
bind:property={variable}
<input bind:value={value} />
<input bind:value />
```
Data ordinarily flows down, from parent to child. The `bind:` directive allows data to flow the other way, from child to parent. Most bindings are specific to particular elements.
Svelte creates an event listener that updates the bound value. If an element already has a listener for the same event, that listener will be fired before the bound value is updated.
Most bindings are _two-way_, meaning that changes to the value will affect the element and vice versa. A few bindings are _readonly_, meaning that changing their value will have no effect on the element.
The simplest bindings reflect the value of a property, such as `input.value`.
## `<input bind:value>`
A `bind:value` directive on an `<input>` element binds the input's `value` property:
<!-- prettier-ignore -->
```svelte
<input bind:value={name} />
<textarea bind:value={text} />
<script>
let message = $state('hello');
</script>
<input type="checkbox" bind:checked={yes} />
<input bind:value={message} />
<p>{message}</p>
```
If the name matches the value, you can use a shorthand.
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)):
```svelte
<input bind:value />
<!-- equivalent to
<input bind:value={value} />
-->
<script>
let a = $state(1);
let b = $state(2);
</script>
<label>
<input type="number" bind:value={a} min="0" max="10" />
<input type="range" bind:value={a} min="0" max="10" />
</label>
<label>
<input type="number" bind:value={b} min="0" max="10" />
<input type="range" bind:value={b} min="0" max="10" />
</label>
<p>{a} + {b} = {a + b}</p>
```
Numeric input values are coerced; even though `input.value` is a string as far as the DOM is concerned, Svelte will treat it as a number. If the input is empty or invalid (in the case of `type="number"`), the value is `undefined`.
If the input is empty or invalid (in the case of `type="number"`), the value is `undefined`.
## `<input bind:checked>`
Checkbox and radio inputs can be bound with `bind:checked`:
```svelte
<input type="number" bind:value={num} />
<input type="range" bind:value={num} />
<label>
<input type="checkbox" bind:checked={accepted} />
Accept terms and conditions
</label>
```
## `<input bind:group>`
Inputs that work together can use `bind:group`.
```svelte
<script>
let tortilla = 'Plain';
/** @type {Array<string>} */
let fillings = [];
</script>
<!-- grouped radio inputs are mutually exclusive -->
<input type="radio" bind:group={tortilla} value="Plain" />
<input type="radio" bind:group={tortilla} value="Whole wheat" />
<input type="radio" bind:group={tortilla} value="Spinach" />
<!-- grouped checkbox inputs populate an array -->
<input type="checkbox" bind:group={fillings} value="Rice" />
<input type="checkbox" bind:group={fillings} value="Beans" />
<input type="checkbox" bind:group={fillings} value="Cheese" />
<input type="checkbox" bind:group={fillings} value="Guac (extra)" />
```
> [!NOTE] `bind:group` only works if the inputs are in the same Svelte component.
## `<input bind:files>`
On `<input>` elements with `type="file"`, you can use `bind:files` to get the [`FileList` of selected files](https://developer.mozilla.org/en-US/docs/Web/API/FileList). When you want to update the files programmatically, you always need to use a `FileList` object. Currently `FileList` objects cannot be constructed directly, so you need to create a new [`DataTransfer`](https://developer.mozilla.org/en-US/docs/Web/API/DataTransfer) object and get `files` from there.
```svelte
@ -62,19 +112,7 @@ On `<input>` elements with `type="file"`, you can use `bind:files` to get the [`
> [!NOTE] `DataTransfer` may not be available in server-side JS runtimes. Leaving the state that is bound to `files` uninitialized prevents potential errors if components are server-side rendered.
If you're using `bind:` directives together with `on` event attributes, the binding will always fire before the event attribute.
```svelte
<script>
let value = 'Hello World';
</script>
<input oninput={() => console.log('New value:', value)} bind:value />
```
Here we were binding to the value of a text input, which uses the `input` event. Bindings on other elements may use different events such as `change`.
## Binding `<select>` value
## `<select bind:value>`
A `<select>` value binding corresponds to the `value` property on the selected `<option>`, which can be any value (not just strings, as is normally the case in the DOM).
@ -108,93 +146,76 @@ When the value of an `<option>` matches its text content, the attribute can be o
</select>
```
Elements with the `contenteditable` attribute support the following bindings:
## `<audio>`
- [`innerHTML`](https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML)
- [`innerText`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/innerText)
- [`textContent`](https://developer.mozilla.org/en-US/docs/Web/API/Node/textContent)
`<audio>` elements have their own set of bindings — five two-way ones...
There are slight differences between each of these, read more about them [here](https://developer.mozilla.org/en-US/docs/Web/API/Node/textContent#Differences_from_innerText).
- [`currentTime`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/currentTime)
- [`playbackRate`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/playbackRate)
- [`paused`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/paused)
- [`volume`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/volume)
- [`muted`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/muted)
<!-- for some reason puts the comment and html on same line -->
<!-- prettier-ignore -->
```svelte
<div contenteditable="true" bind:innerHTML={html} />
```
...and seven readonly ones:
`<details>` elements support binding to the `open` property.
- [`duration`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/duration)
- [`buffered`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/buffered)
- [`paused`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/paused)
- [`seekable`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/seekable)
- [`seeking`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/seeking_event)
- [`ended`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/ended)
- [`readyState`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/readyState)
```svelte
<details bind:open={isOpen}>
<summary>Details</summary>
<p>Something small enough to escape casual notice.</p>
</details>
<audio src={clip} bind:duration bind:currentTime bind:paused></audio>
```
## Media element bindings
## `<video>`
Media elements (`<audio>` and `<video>`) have their own set of bindings — seven _readonly_ ones...
`<video>` elements have all the same bindings as [#audio] elements, plus readonly [`videoWidth`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLVideoElement/videoWidth) and [`videoHeight`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLVideoElement/videoHeight) bindings.
- `duration` (readonly) — the total duration of the video, in seconds
- `buffered` (readonly) — an array of `{start, end}` objects
- `played` (readonly) — ditto
- `seekable` (readonly) — ditto
- `seeking` (readonly) — boolean
- `ended` (readonly) — boolean
- `readyState` (readonly) — number between (and including) 0 and 4
## `<img>`
...and five _two-way_ bindings:
`<img>` elements have two readonly bindings:
- `currentTime` — the current playback time in the video, in seconds
- `playbackRate` — how fast or slow to play the video, where 1 is 'normal'
- `paused` — this one should be self-explanatory
- `volume` — a value between 0 and 1
- `muted` — a boolean value indicating whether the player is muted
- [`naturalWidth`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/naturalWidth)
- [`naturalHeight`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/naturalHeight)
Videos additionally have readonly `videoWidth` and `videoHeight` bindings.
## `<details bind:open>`
`<details>` elements support binding to the `open` property.
```svelte
<video
src={clip}
bind:duration
bind:buffered
bind:played
bind:seekable
bind:seeking
bind:ended
bind:readyState
bind:currentTime
bind:playbackRate
bind:paused
bind:volume
bind:muted
bind:videoWidth
bind:videoHeight
/>
<details bind:open={isOpen}>
<summary>How do you comfort a JavaScript bug?</summary>
<p>You console it.</p>
</details>
```
## Image element bindings
## Contenteditable bindings
Image elements (`<img>`) have two readonly bindings:
Elements with the `contenteditable` attribute support the following bindings:
- `naturalWidth` (readonly) — the original width of the image, available after the image has loaded
- `naturalHeight` (readonly) — the original height of the image, available after the image has loaded
- [`innerHTML`](https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML)
- [`innerText`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/innerText)
- [`textContent`](https://developer.mozilla.org/en-US/docs/Web/API/Node/textContent)
> [!NOTE] There are [subtle differences between `innerText` and `textContent`](https://developer.mozilla.org/en-US/docs/Web/API/Node/textContent#differences_from_innertext).
<!-- for some reason puts the comment and html on same line -->
<!-- prettier-ignore -->
```svelte
<img
bind:naturalWidth
bind:naturalHeight
></img>
<div contenteditable="true" bind:innerHTML={html} />
```
## Block-level element bindings
## Dimensions
Block-level elements have 4 read-only bindings, measured using a technique similar to [this one](http://www.backalleycoder.com/2013/03/18/cross-browser-event-based-element-resize-detection/):
All visible elements have the following readonly bindings, measured with a `ResizeObserver`:
- `clientWidth`
- `clientHeight`
- `offsetWidth`
- `offsetHeight`
- [`clientWidth`](https://developer.mozilla.org/en-US/docs/Web/API/Element/clientWidth)
- [`clientHeight`](https://developer.mozilla.org/en-US/docs/Web/API/Element/clientHeight)
- [`offsetWidth`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/offsetWidth)
- [`offsetHeight`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/offsetHeight)
```svelte
<div bind:offsetWidth={width} bind:offsetHeight={height}>
@ -202,37 +223,6 @@ Block-level elements have 4 read-only bindings, measured using a technique simil
</div>
```
## bind:group
```svelte
<!--- copy: false --->
bind:group={variable}
```
Inputs that work together can use `bind:group`.
```svelte
<script>
let tortilla = 'Plain';
/** @type {Array<string>} */
let fillings = [];
</script>
<!-- grouped radio inputs are mutually exclusive -->
<input type="radio" bind:group={tortilla} value="Plain" />
<input type="radio" bind:group={tortilla} value="Whole wheat" />
<input type="radio" bind:group={tortilla} value="Spinach" />
<!-- grouped checkbox inputs populate an array -->
<input type="checkbox" bind:group={fillings} value="Rice" />
<input type="checkbox" bind:group={fillings} value="Beans" />
<input type="checkbox" bind:group={fillings} value="Cheese" />
<input type="checkbox" bind:group={fillings} value="Guac (extra)" />
```
> [!NOTE] `bind:group` only works if the inputs are in the same Svelte component.
## bind:this
```svelte
@ -240,22 +230,20 @@ Inputs that work together can use `bind:group`.
bind:this={dom_node}
```
To get a reference to a DOM node, use `bind:this`.
To get a reference to a DOM node, use `bind:this`. The value will be `undefined` until the component is mounted — in other words, you should read it inside an effect or an event handler, but not during component initialisation:
```svelte
<script>
import { onMount } from 'svelte';
/** @type {HTMLCanvasElement} */
let canvasElement;
let canvas;
onMount(() => {
const ctx = canvasElement.getContext('2d');
$effect(() => {
const ctx = canvas.getContext('2d');
drawStuff(ctx);
});
</script>
<canvas bind:this={canvasElement} />
<canvas bind:this={canvas} />
```
Components also support `bind:this`, allowing you to interact with component instances programmatically.
@ -277,8 +265,6 @@ Components also support `bind:this`, allowing you to interact with component ins
</script>
```
> [!NOTE] Note that we can't do `{cart.empty}` since `cart` is `undefined` when the button is first rendered and throws an error.
## bind:_property_ for components
```svelte

@ -1,5 +1,5 @@
---
title: Transitions & Animations
title: transition:
---
- how to use (template syntax)
@ -310,7 +310,7 @@ DOMRect {
}
```
An animation is triggered when the contents of a [keyed each block](control-flow#each) are re-ordered. Animations do not run when an element is added or removed, only when the index of an existing data item within the each block changes. Animate directives must be on an element that is an _immediate_ child of a keyed each block.
An animation is triggered when the contents of a [keyed each block](each) are re-ordered. Animations do not run when an element is added or removed, only when the index of an existing data item within the each block changes. Animate directives must be on an element that is an _immediate_ child of a keyed each block.
Animations can be used with Svelte's [built-in animation functions](svelte-animate) or [custom animation functions](#Custom-animation-functions).
@ -408,28 +408,3 @@ A custom animation function can also return a `tick` function, which is called _
<div animate:whizz>{item}</div>
{/each}
```
## {#key ...}
```svelte
<!--- copy: false --->
{#key expression}...{/key}
```
Key blocks destroy and recreate their contents when the value of an expression changes.
This is useful if you want an element to play its transition whenever a value changes.
```svelte
{#key value}
<div transition:fade>{value}</div>
{/key}
```
When used around components, this will cause them to be reinstantiated and reinitialised.
```svelte
{#key value}
<Component />
{/key}
```

@ -0,0 +1,5 @@
---
title: in: and out:
---
Coming soon!

@ -0,0 +1,5 @@
---
title: animate:
---
Coming soon!

@ -0,0 +1,5 @@
---
title: class: and style:
---
Coming soon!

@ -17,43 +17,6 @@ The syntax between these blocks is the same:
## {#if ...}
```svelte
<!--- copy: false --->
{#if expression}...{/if}
```
```svelte
<!--- copy: false --->
{#if expression}...{:else if expression}...{/if}
```
```svelte
<!--- copy: false --->
{#if expression}...{:else}...{/if}
```
Content that is conditionally rendered can be wrapped in an if block.
```svelte
{#if answer === 42}
<p>what was the question?</p>
{/if}
```
Additional conditions can be added with `{:else if expression}`, optionally ending in an `{:else}` clause.
```svelte
{#if porridge.temperature > 100}
<p>too hot!</p>
{:else if 80 > porridge.temperature}
<p>too cold!</p>
{:else}
<p>just right!</p>
{/if}
```
(Blocks don't have to wrap elements, they can also wrap text within elements!)
## {#each ...}
```svelte

@ -0,0 +1,20 @@
---
title: Data fetching
---
Fetching data is a fundamental part of apps interacting with the outside world. Svelte is unopinionated with how you fetch your data. The simplest way would be using the built-in `fetch` method:
```svelte
<script>
let response = $state();
fetch('/api/data').then(async (r) => (response = r.json()));
</script>
```
While this works, it makes working with promises somewhat unergonomic. Svelte alleviates this problem using the `#await` block.
## {#await ...}
## SvelteKit loaders
Fetching inside your components is great for simple use cases, but it's prone to data loading waterfalls and makes code harder to work with because of the promise handling. SvelteKit solves this problem by providing a opinionated data loading story that is coupled to its router. Learn more about it [in the docs](../kit).

@ -0,0 +1,3 @@
---
title: Styling
---

@ -1,94 +0,0 @@
---
title: Debugging
---
- `@debug`
- `$inspect`
Svelte provides two built-in ways to debug your application.
## `$inspect`
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:](/#H4sIAAAAAAAACkWQ0YqDQAxFfyUMhSotdZ-tCvu431AXtGOqQ2NmmMm0LOK_r7Utfby5JzeXTOpiCIPKT5PidkSVq2_n1F7Jn3uIcEMSXHSw0evHpAjaGydVzbUQCmgbWaCETZBWMPlKj29nxBDaHj_edkAiu12JhdkYDg61JGvE_s2nR8gyuBuiJZuDJTyQ7eE-IEOzog1YD80Lb0APLfdYc5F9qnFxjiKWwbImo6_llKRQVs-2u91c_bD2OCJLkT3JZasw7KLA2XCX31qKWE6vIzNk1fKE0XbmYrBTufiI8-_8D2cUWBA_AQAA))
```svelte
<script>
let count = $state(0);
let message = $state('hello');
$inspect(count, message); // will console.log when `count` or `message` change
</script>
<button onclick={() => count++}>Increment</button>
<input bind:value={message} />
```
`$inspect` returns a property `with`, which you can invoke with a callback, which will then be invoked instead of `console.log`. The first argument to the callback is either `"init"` or `"update"`, all following arguments are the values passed to `$inspect`. [Demo:](/#H4sIAAAAAAAACkVQ24qDMBD9lSEUqlTqPlsj7ON-w7pQG8c2VCchmVSK-O-bKMs-DefKYRYx6BG9qL4XQd2EohKf1opC8Nsm4F84MkbsTXAqMbVXTltuWmp5RAZlAjFIOHjuGLOP_BKVqB00eYuKs82Qn2fNjyxLtcWeyUE2sCRry3qATQIpJRyD7WPVMf9TW-7xFu53dBcoSzAOrsqQNyOe2XUKr0Xi5kcMvdDB2wSYO-I9vKazplV1-T-d6ltgNgSG1KjVUy7ZtmdbdjqtzRcphxMS1-XubOITJtPrQWMvKnYB15_1F7KKadA_AQAA)
```svelte
<script>
let count = $state(0);
$inspect(count).with((type, count) => {
if (type === 'update') {
debugger; // or `console.trace`, or whatever you want
}
});
</script>
<button onclick={() => count++}>Increment</button>
```
A convenient way to find the origin of some change is to pass `console.trace` to `with`:
```js
// @errors: 2304
$inspect(stuff).with(console.trace);
```
> [!NOTE] `$inspect` only works during development. In a production build it becomes a noop.
## @debug
```svelte
<!--- copy: false --->
{@debug}
```
```svelte
<!--- copy: false --->
{@debug var1, var2, ..., varN}
```
The `{@debug ...}` tag offers an alternative to `console.log(...)`. It logs the values of specific variables whenever they change, and pauses code execution if you have devtools open.
```svelte
<script>
let user = {
firstname: 'Ada',
lastname: 'Lovelace'
};
</script>
{@debug user}
<h1>Hello {user.firstname}!</h1>
```
`{@debug ...}` accepts a comma-separated list of variable names (not arbitrary expressions).
```svelte
<!-- Compiles -->
{@debug user}
{@debug user1, user2, user3}
<!-- WON'T compile -->
{@debug user.firstname}
{@debug myArray[0]}
{@debug !isReady}
{@debug typeof user === 'object'}
```
The `{@debug}` tag without any arguments will insert a `debugger` statement that gets triggered when _any_ state changes, as opposed to the specified variables.

@ -1,5 +0,0 @@
---
title: Svelte 5 migration guide
---
- the stuff from the preview docs and possibly more

@ -122,7 +122,7 @@ All except `scrollX` and `scrollY` are readonly.
<svelte:document bind:prop={value} />
```
Similarly to `<svelte:window>`, this element allows you to add listeners to events on `document`, such as `visibilitychange`, which don't fire on `window`. It also lets you use [actions](actions) on `document`.
Similarly to `<svelte:window>`, this element allows you to add listeners to events on `document`, such as `visibilitychange`, which don't fire on `window`. It also lets you use [actions](use) on `document`.
As with `<svelte:window>`, this element may only appear the top level of your component and must never be inside a block or element.
@ -145,7 +145,7 @@ All are readonly.
<svelte:body onevent={handler} />
```
Similarly to `<svelte:window>`, this element allows you to add listeners to events on `document.body`, such as `mouseenter` and `mouseleave`, which don't fire on `window`. It also lets you use [actions](actions) on the `<body>` element.
Similarly to `<svelte:window>`, this element allows you to add listeners to events on `document.body`, such as `mouseenter` and `mouseleave`, which don't fire on `window`. It also lets you use [actions](use) on the `<body>` element.
As with `<svelte:window>` and `<svelte:document>`, this element may only appear the top level of your component and must never be inside a block or element.

@ -0,0 +1,3 @@
---
title: Special elements
---

@ -0,0 +1,55 @@
---
title: Debugging
---
- `@debug`
- `$inspect`
Svelte provides two built-in ways to debug your application.
## `$inspect`
TODO
## @debug
```svelte
<!--- copy: false --->
{@debug}
```
```svelte
<!--- copy: false --->
{@debug var1, var2, ..., varN}
```
The `{@debug ...}` tag offers an alternative to `console.log(...)`. It logs the values of specific variables whenever they change, and pauses code execution if you have devtools open.
```svelte
<script>
let user = {
firstname: 'Ada',
lastname: 'Lovelace'
};
</script>
{@debug user}
<h1>Hello {user.firstname}!</h1>
```
`{@debug ...}` accepts a comma-separated list of variable names (not arbitrary expressions).
```svelte
<!-- Compiles -->
{@debug user}
{@debug user1, user2, user3}
<!-- WON'T compile -->
{@debug user.firstname}
{@debug myArray[0]}
{@debug !isReady}
{@debug typeof user === 'object'}
```
The `{@debug}` tag without any arguments will insert a `debugger` statement that gets triggered when _any_ state changes, as opposed to the specified variables.

@ -187,7 +187,7 @@ When writing component tests that involve two-way bindings, context or snippet p
E2E (short for 'end to end') tests allow you to test your full application through the eyes of the user. This section uses [Playwright](https://playwright.dev/) as an example, but you can also use other solutions like [Cypress](https://www.cypress.io/) or [NightwatchJS](https://nightwatchjs.org/).
To get start with Playwright, either let you guide by [their VS Code extension](https://playwright.dev/docs/getting-started-vscode), or install it from the command line using `npm init playwright`. It is also part of the setup CLI when you run `npm create svelte`.
To get start with Playwright, either let you guide by [their VS Code extension](https://playwright.dev/docs/getting-started-vscode), or install it from the command line using `npm init playwright`. It is also part of the setup CLI when you run `npx sv create`.
After you've done that, you should have a `tests` folder and a Playwright config. You may need to adjust that config to tell Playwright what to do before running the tests - mainly starting your application at a certain port:

@ -42,7 +42,7 @@ To use non-type-only TypeScript features within Svelte components, you need to a
### Using SvelteKit or Vite
The easiest way to get started is scaffolding a new SvelteKit project by typing `npm create svelte@latest`, following the prompts and choosing the TypeScript option.
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
@ -170,7 +170,7 @@ Using it together with `<svelte:component>` to restrict what kinds of component
interface Props {
// only components that have at most the "prop"
// property required can be passed
component: Component<{ prop: string }>
component: Component<{ prop: string }>;
}
let { component }: Props = $props();
@ -211,7 +211,7 @@ declare namespace svelteHTML {
// enhance attributes
interface HTMLAttributes<T> {
// If you want to use the beforeinstallprompt event
'onbeforeinstallprompt'?: (event: any) => any;
onbeforeinstallprompt?: (event: any) => any;
// If you want to use myCustomAttribute={..} (note: all lowercase)
mycustomattribute?: any; // You can replace any with something more specific if you like
}

@ -0,0 +1,920 @@
---
title: Svelte 5 migration guide
---
Version 5 comes with an overhauled syntax and reactivity system. While it may look different at first, you'll soon notice many similarities. This guide goes over the changes in detail and shows you how to upgrade. Along with it, we also provide information on _why_ we did these changes.
You don't have to migrate to the new syntax right away - Svelte 5 still supports the old Svelte 4 syntax, and you can mix and match components using the new syntax with components using the old and vice versa. We expect many people to be able to upgrade with only a few lines of code changed initially. There's also a [migration script](#Migration-script) that helps you with many of these steps automatically.
## Reactivity syntax changes
At the heart of Svelte 5 is the new runes API. Runes are basically compiler instructions that inform Svelte about reactivity. Syntactically, runes are functions starting with a dollar-sign.
### let -> $state
In Svelte 4, a `let` declaration at the top level of a component was implicitly reactive. In Svelte 5, things are more explicit: a variable is reactive when created using the `$state` rune. Let's migrate the counter to runes mode by wrapping the counter in `$state`:
```svelte
<script>
let count = +++$state(+++0+++)+++;
</script>
```
Nothing else changes. `count` is still the number itself, and you read and write directly to it, without a wrapper like `.value` or `getCount()`.
> [!DETAILS] Why we did this
> `let` being implicitly reactive at the top level worked great, but it meant that reactivity was constrained - a `let` declaration anywhere else was not reactive. This forced you to resort to using stores when refactoring code out of the top level of components for reuse. This meant you had to learn an entirely separate reactivity model, and the result often wasn't as nice to work with. Because reactivity is more explicit in Svelte 5, you can keep using the same API in an outside the top level of components. Head to TODO LINK TO TUTORIAL to learn more.
### $: -> $derived/$effect
In Svelte 4, a `$:` statement at the top level of a component could be used to declare a derivation, i.e. state that is entirely defined through a computation of other state. In Svelte 5, this is achieved using the `$derived` rune:
```svelte
<script>
let count = +++$state(+++0+++)+++;
---$:--- +++const+++ double = +++$derived(+++count * 2+++)+++;
</script>
```
As with `$state`, nothing else changes. `double` is still the number itself, and you read it directly, without a wrapper like `.value` or `getCount()`.
A `$:` statement could also be used to create side effects. In Svelte 5, this is achieved using the `$effect` rune:
```svelte
<script>
let count = +++$state(+++0+++)+++;
---$:---+++$effect(() =>+++ {
if (count > 5) {
alert('Count is too high!');
}
}+++);+++
</script>
```
> [!DETAILS] Why we did this
> `$:` was a great shorthand and easy to get started with: you could slap a `$:` in front of most code and it would somehow work. This intuitiveness was also its drawback the more complicated your code became, because it wasn't as easy to reason about. Was the intent of the code to create a derivation, or a side effect? With `$derived` and `$effect`, you have a bit more up-front decision making to do (spoiler alert: 90% of the time you want `$derived`), but future-you and other developers on your team will have an easier time.
>
> There were also gotchas that were hard to spot:
>
> - `$:` only updated directly before rendering, which meant you could read stale values in-between rerenders
> - `$:` only ran once per tick, which meant that statements may run less often than you think
> - `$:` dependencies were determined through static analysis of the dependencies. This worked in most cases, but could break in subtle ways during a refactoring where dependencies would be > for example moved into a function and no longer be visible as a result
> - `$:` statements were also ordered by using static analysis of the dependencies. In some cases there could be ties and the ordering would be wrong as a result, needing manual > interventions. Ordering could also break while refactoring code and some dependencies no longer being visible as a result.
>
> Lastly, it wasn't TypeScript-friendly (our editor tooling had to jump through some hoops to make it valid for TypeScript), which was a blocker for making Svelte's reactivity model truly > universal.
>
> `$derived` and `$effect` fix all of these by
>
> - always returning the latest value
> - running as often as needed to be stable
> - determining the dependencies at runtime, and therefore being immune to refactorings
> - executing dependencies as needed and therefore being immune to ordering problems
> - being TypeScript-friendly
### export let -> $props
In Svelte 4, properties of a component were declared using `export let`. Each property was one declaration. In Svelte 5, all properties are declared through the `$props` rune, through destructuring:
```svelte
<script>
---export let optional = 'unset';
export let required;---
+++let { optional = 'unset', required } = $props();+++
</script>
```
There are multiple cases where declaring properties becomes less straightforward than having a few `export let` declarations:
- you want to rename the property, for example because the name is a reserved identifier (e.g. `class`)
- you don't know which other properties to expect in advance
- you want to forward every property to another component
All these cases need special syntax in Svelte 4:
- renaming: `export { klass as class}`
- other properties: `$$restProps`
- all properties `$$props`
In Svelte 5, the `$props` rune makes this straightforward without any additional Svelte-specific syntax:
- renaming: use property renaming `let { class: klass } = $props();`
- other properties: use spreading `let { foo, bar, ...rest } = $props();`
- all properties: don't destructure `let props = $props();`
```svelte
<script>
---let klass = '';
export { klass as class};---
+++let { class: klass, ...rest } = $props();+++
</script>
<button {class} {...---$$restProps---+++rest+++}>click me</button>
```
> [!DETAILS] Why we did this
> `export let` was one of the more controversial API decisions, and there was a lot of debate about whether you should think about a property being `export`ed or `import`ed. `$props` doesn't have this trait. It's also in line with the other runes, and the general thinking reduces to "everything special to reactivity in Svelte is a rune".
>
> There were also a lot of limitations around `export let`, which required additional API, as shown above. `$props` unite this in one syntactical concept that leans heavily on regular JavaScript destructuring syntax.
## Event changes
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 (in other words - remove the colon):
```svelte
<script>
let count = $state(0);
</script>
<button on---:---click={() => count++}>
clicks: {count}
</button>
```
Since they're just properties, you can use the normal shorthand syntax...
```svelte
<script>
let count = $state(0);
function onclick() {
count++;
}
</script>
<button {onclick}>
clicks: {count}
</button>
```
...though when using a named event handler function it's usually better to use a more descriptive name.
### Component events
In Svelte 4, components could emit events by creating a dispatcher with `createEventDispatcher`.
This function is deprecated in Svelte 5. Instead, components should accept _callback props_ - which means you then pass functions as properties to these components:
```svelte
<!--- file: App.svelte --->
<script>
import Pump from './Pump.svelte';
let size = $state(15);
let burst = $state(false);
function reset() {
size = 15;
burst = false;
}
</script>
<Pump
---on:---inflate={(power) => {
size += power---.details---;
if (size > 75) burst = true;
}}
---on:---deflate={(power) => {
if (size > 0) size -= power---.details---;
}}
/>
{#if burst}
<button onclick={reset}>new balloon</button>
<span class="boom">💥</span>
{:else}
<span class="balloon" style="scale: {0.01 * size}">
🎈
</span>
{/if}
```
```svelte
<!--- file: Pump.svelte --->
<script>
---import { createEventDispatcher } from 'svelte';
const dispatch = createEventDispatcher();
---
+++let { inflate, deflate } = $props();+++
let power = $state(5);
</script>
<button onclick={() => ---dispatch('inflate', power)---+++inflate(power)+++}>
inflate
</button>
<button onclick={() => ---dispatch('deflate', power)---+++deflate(power)+++}>
deflate
</button>
<button onclick={() => power--}>-</button>
Pump power: {power}
<button onclick={() => power++}>+</button>
```
### Bubbling events
Instead of doing `<button on:click>` to 'forward' the event from the element to the component, the component should accept an `onclick` callback prop:
```svelte
<script>
+++let { onclick } = $props();+++
</script>
<button ---on:click--- +++{onclick}+++>
click me
</button>
```
Note that this also means you can 'spread' event handlers onto the element along with other props instead of tediously forwarding each event separately:
```svelte
<script>
let props = $props();
</script>
<button ---{...$$props} on:click on:keydown on:all_the_other_stuff--- +++{...props}+++>
click me
</button>
```
### Event modifiers
In Svelte 4, you can add event modifiers to handlers:
```svelte
<button on:click|once|preventDefault={handler}>...</button>
```
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.
Since event handlers are just functions, you can create your own wrappers as necessary:
```svelte
<script>
function once(fn) {
return function (event) {
if (fn) fn.call(this, event);
fn = null;
};
}
function preventDefault(fn) {
return function (event) {
event.preventDefault();
fn.call(this, event);
};
}
</script>
<button onclick={once(preventDefault(handler))}>...</button>
```
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.
For `capture`, we add the modifier to the event name:
```svelte
<button onclickcapture={...}>...</button>
```
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.
### Multiple event handlers
In Svelte 4, this is possible:
```svelte
<button on:click={one} on:click={two}>...</button>
```
Duplicate attributes/properties on elements — which now includes event handlers — are not allowed. Instead, do this:
```svelte
<button
onclick={(e) => {
one(e);
two(e);
}}
>
...
</button>
```
When spreading props, local event handlers must go _after_ the spread, or they risk being overwritten:
```svelte
<button
{...props}
onclick={(e) => {
doStuff(e);
props.onclick?.(e);
}}
>
...
</button>
```
> [!DETAILS] Why we did this
> `createEventDispatcher` was always a bit boilerplate-y:
>
> - import the function
> - call the function to get a dispatch function
> - call said dispatch function with a string and possibly a payload
> - retrieve said payload on the other end through a `.details` property, because the event itself was always a `CustomEvent`
>
> It was always possible to use component callback props, but because you had to listen to dom events using `on:`, it made sense to use `createEventDispatcher` for component events due to > syntactical consiscency. Now that we have event attributes (`onclick`), it's the other way around: Callback props are now the more sensible thing to do.
>
> The removal of event modifiers is arguably one of the changes that seems like a step back for those who've liked the shorthand syntax of event modifiers. Given that they are not used that > frequently, we traded a smaller surface area for more explicitness. Modifiers also were inconsistent, because most of them were only useable on Dom elements.
>
> Multiple listeners for the same event are also no longer possible, but it was something of an anti-pattern anyway, 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. It also implies that the two handlers are independent, when in fact something like `event.> stopImmediatePropagation()` inside `one` would prevent `two` from being called.
>
> By deprecating `createEventDispatcher` and the `on:` directive in favour of callback props and normal element properties, we:
>
> - reduce Svelte's learning curve
> - remove boilerplate, particularly around `createEventDispatcher`
> - remove the overhead of creating `CustomEvent` objects for events that may not even have listeners
> - add the ability to spread event handlers
> - add the ability to know which event handlers were provided to a component
> - add the ability to express whether a given event handler is required or optional
> - increase type safety (previously, it was effectively impossible for Svelte to guarantee that a component didn't emit a particular event)
## Snippets instead of slots
In Svelte 4, content can be passed to components using slots. Svelte 5 replaces them with snippets which are more powerful and flexible, and as such slots are deprecated in Svelte 5.
They continue to work, however, and you can mix and match snippets and slots in your components.
When using custom elements, you should still use `<slot />` like before. In a future version, when Svelte removes its internal version of slots, it will leave those slots as-is, i.e. output a regular DOM tag instead of transforming it.
### Default content
In Svelte 4, the easiest way to pass a piece of UI to the child was using a `<slot />`. In Svelte 5, this is done using the `children` prop instead, which is then shown with `{@render children()}`:
```svelte
<script>
+++let { children } = $props();+++
</script>
---<slot />---
+++{@render children?.()}+++
```
### Multiple content placeholders
If you wanted multiple UI placeholders, you had to use named slots. In Svelte 5, use props instead, name them however you like and `{@render ...}` them:
```svelte
<script>
+++let { header, main, footer } = $props();+++
</script>
<header>
---<slot name="header" />---
+++{@render header()}+++
</header>
<main>
---<slot name="main" />---
+++{@render main()}+++
</main>
<footer>
---<slot name="header" />---
+++{@render footer()}+++
</footer>
```
### Passing data back up
In Svelte 4, you would pass data to a `<slot />` and then retrieve it with `let:` in the parent component. In Svelte 5, snippets take on that responsibility:
```svelte
<!--- file: App.svelte --->
<script>
import List from './List.svelte';
</script>
<List items={['one', 'two', 'three']} ---let:item--->
+++{#snippet item(text)}+++
<span>{text}</span>
+++{/snippet}+++
---<span slot="empty">No items yet</span>---
+++{#snippet empty()}
<span>No items yet</span>
{/snippet}+++
</List>
```
```svelte
<!--- file: List.svelte --->
<script>
let { items, +++item, empty+++ } = $props();
</script>
{#if items.length}
<ul>
{#each items as entry}
<li>
---<slot item={entry} />---
+++{@render item(entry)}+++
</li>
{/each}
</ul>
{:else}
---<slot name="empty" />---
+++{@render empty?.()}+++
{/if}
```
> [!DETAILS] Why we did this
> Slots were easy to get started with, but the more advanced the use case became, the more involved and confusing the syntax became:
>
> - the `let:` syntax was confusing to many people as it _creates_ a variable whereas all other `:` directives _receive_ a variable
> - the scope of a variable declared with `let:` wasn't clear. In the example above, it may look like you can use the `item` slot prop in the `empty` slot, but that's not true
> - named slots had to be applied to an element using the `slot` attribute. Sometimes you didn't want to create an element, so we had to add the `<svelte:fragment>` API
> - named slots could also be applied to a component, which changed the semantics of where `let:` directives are available (even today us maintainers often don't know which way around it > works)
>
> Snippets solve all of these problems by being much more readable and clear. At the same time they're more powerful as they allow you to define sections of UI that you can render _anywhere_, not just passing them as props to a component.
## Migration script
By now you should have a pretty good understanding of the before/after and how the old syntax relates to the new syntax. It probably also became clear that a lot of these migrations are rather technical and repetitive - something you don't want to do by hand.
We thought the same, which is why we provide a migration script to do most of the migration automatically. You can upgrade your project by using `npx sv migrate svelte-5`. This will do the following things:
- bump core dependencies in your `package.json`
- migrate to runes (`let` -> `$state` etc)
- migrate to event attributes for Dom elements (`on:click` -> `onclick`)
- migrate slot creations to render tags (`<slot />` -> `{@render children()}`)
- migrate slot usages to snippets (`<div slot="x">...</div>` -> `{#snippet x()}<div>...</div>{/snippet}`)
- migrate obvious component creations (`new Component(...)` -> `mount(Component, ...)`)
You can also migrate a single component in VS Code through the `Migrate Component to Svelte 5 Syntax` command, or in our Playground through the `Migrate` button.
Not everything can be migrated automatically, and some migrations need manual cleanup afterwards. The following sections describe these in more detail.
### run
You may see that the migration script converts some of your `$:` statements to a `run` function which is imported from `svelte/legacy`. This happens if the migration script couldn't reliably migrate the statement to a `$derived` and concluded this is a side effect instead. In some cases this may be wrong and it's best to change this to use a `$derived` instead. In other cases it may be right, but since `$:` statements also ran on the server but `$effect` does not, it isn't safe to transform it as such. Instead, `run` is used as a stopgap solution. `run` mimics most of the characteristics of `$:`, in that it runs on the server once, and runs as `$effect.pre` on the client (`$effect.pre` runs _before_ changes are applied to the DOM; most likely you want to use `$effect` instead).
```svelte
<script>
---import { run } from 'svelte/legacy';---
---run(() => {---
+++$effect(() => {+++
// some side effect code
})
</script>
```
### Event modifiers
Event modifiers are not applicable to event attributes (e.g. you can't do `onclick|preventDefault={...}`). Therefore, when migrating event directives to event attributes, we need a function-replacement for these modifiers. These are imported from `svelte/legacy`, and should be migrated away from in favor of e.g. just using `event.preventDefault()`.
```svelte
<script>
---import { preventDefault } from 'svelte/legacy';---
</script>
<button
onclick={---preventDefault---((event) => {
+++event.preventDefault();+++
// ...
})}
>
click me
</button>
```
### Things that are not automigrated
The migration script does not convert `createEventDispatcher`. You need to adjust those parts manually. It doesn't do it because it's too risky because it could result in breakage for users of the component, which the migration script cannot find out.
The migration script does not convert `beforeUpdate/afterUpdate`. It doesn't do it because it's impossible to determine the actual intent of the code. As a rule of thumb you can often go with a combination of `$effect.pre` (runs at the same time as `beforeUpdate` did) and `tick` (imported from `svelte`, allows you to wait until changes are applied to the DOM and then do some work).
## Components are no longer classes
In Svelte 3 and 4, components are classes. In Svelte 5 they are functions and should be instantiated differently. If you need to manually instantiate components, you should use `mount` or `hydrate` (imported from `svelte`) instead. If you see this error using SvelteKit, try updating to the latest version of SvelteKit first, which adds support for Svelte 5. If you're using Svelte without SvelteKit, you'll likely have a `main.js` file (or similar) which you need to adjust:
```js
+++import { mount } from 'svelte';+++
import App from './App.svelte'
---const app = new App({ target: document.getElementById("app") });---
+++const app = mount(App, { target: document.getElementById("app") });+++
export default app;
```
`mount` and `hydrate` have the exact same API. The difference is that `hydrate` will pick up the Svelte's server-rendered HTML inside its target and hydrate it. Both return an object with the exports of the component and potentially property accessors (if compiled with `accessors: true`). They do not come with the `$on`, `$set` and `$destroy` methods you may know from the class component API. These are its replacements:
For `$on`, instead of listening to events, pass them via the `events` property on the options argument.
```js
+++import { mount } from 'svelte';+++
import App from './App.svelte'
---const app = new App({ target: document.getElementById("app") });
app.$on('event', callback);---
+++const app = mount(App, { target: document.getElementById("app"), events: { event: callback } });+++
```
> [!NOTE] Note that using `events` is discouraged — instead, [use callbacks](#Event-changes)
For `$set`, use `$state` instead to create a reactive property object and manipulate it. If you're doing this inside a `.js` or `.ts` file, adjust the ending to include `.svelte`, i.e. `.svelte.js` or `.svelte.ts`.
```js
+++import { mount } from 'svelte';+++
import App from './App.svelte'
---const app = new App({ target: document.getElementById("app"), props: { foo: 'bar' } });
app.$set('event', { foo: 'baz' });---
+++const props = $state({ foo: 'bar' });
const app = mount(App, { target: document.getElementById("app"), props });
props.foo = 'baz';+++
```
For `$destroy`, use `unmount` instead.
```js
+++import { mount, unmount } from 'svelte';+++
import App from './App.svelte'
---const app = new App({ target: document.getElementById("app"), props: { foo: 'bar' } });
app.$destroy();---
+++const app = mount(App, { target: document.getElementById("app") });
unmount(app);+++
```
As a stop-gap-solution, you can also use `createClassComponent` or `asClassComponent` (imported from `svelte/legacy`) instead to keep the same API known from Svelte 4 after instantiating.
```js
+++import { createClassComponent } from 'svelte/legacy';+++
import App from './App.svelte'
---const app = new App({ target: document.getElementById("app") });---
+++const app = createClassComponent({ component: App, target: document.getElementById("app") });+++
export default app;
```
If this component is not under your control, you can use the `compatibility.componentApi` compiler option for auto-applied backwards compatibility, which means code using `new Component(...)` keeps working without adjustments (note that this adds a bit of overhead to each component). This will also add `$set` and `$on` methods for all component instances you get through `bind:this`.
```js
/// svelte.config.js
export default {
compilerOptions: {
compatibility: {
componentApi: 4
}
}
};
```
Note that `mount` and `hydrate` are _not_ synchronous, so things like `onMount` won't have been called by the time the function returns and the pending block of promises will not have been rendered yet (because `#await` waits a microtask to wait for a potentially immediately-resolved promise). If you need that guarantee, call `flushSync` (import from `'svelte'`) after calling `mount/hydrate`.
### Server API changes
Similarly, components no longer have a `render` method when compiled for server side rendering. Instead, pass the function to `render` from `svelte/server`:
```js
+++import { render } from 'svelte/server';+++
import App from './App.svelte';
---const { html, head } = App.render({ props: { message: 'hello' }});---
+++const { html, head } = render(App, { props: { message: 'hello' }});+++
```
In Svelte 4, rendering a component to a string also returned the CSS of all components. In Svelte 5, this is no longer the case by default because most of the time you're using a tooling chain that takes care of it in other ways (like SvelteKit). If you need CSS to be returned from `render`, you can set the `css` compiler option to `'injected'` and it will add `<style>` elements to the `head`.
### Component typing changes
The change from classes towards functions is also reflected in the typings: `SvelteComponent`, the base class from Svelte 4, is deprecated in favour of the new `Component` type which defines the function shape of a Svelte component. To manually define a component shape in a `d.ts` file:
```ts
import type { Component } from 'svelte';
export declare const MyComponent: Component<{
foo: string;
}>;
```
To declare that a component of a certain type is required:
```svelte
<script lang="ts">
import type { Component } from 'svelte';
import {
ComponentA,
ComponentB
} from 'component-library';
let component: Component<{ foo: string }> = $state(
Math.random() ? ComponentA : ComponentB
);
</script>
<svelte:component this={component} foo="bar" />
```
The two utility types `ComponentEvents` and `ComponentType` are also deprecated. `ComponentEvents` is obsolete because events are defined as callback props now, and `ComponentType` is obsolete because the new `Component` type is the component type already (e.g. `ComponentType<SvelteComponent<{ prop: string }>>` == `Component<{ prop: string }>`).
### bind:this changes
Because components are no longer classes, using `bind:this` no longer returns a class instance with `$set`, `$on` and `$destroy` methods on it. It only returns the instance exports (`export function/const`) and, if you're using the `accessors` option, a getter/setter-pair for each property.
## Whitespace handling changed
Previously, Svelte employed a very complicated algorithm to determine if whitespace should be kept or not. Svelte 5 simplifies this which makes it easier to reason about as a developer. The rules are:
- Whitespace between nodes is collapsed to one whitespace
- Whitespace at the start and end of a tag is removed completely
- Certain exceptions apply such as keeping whitespace inside `pre` tags
As before, you can disable whitespace trimming by setting the `preserveWhitespace` option in your compiler settings or on a per-component basis in `<svelte:options>`.
## Modern browser required
Svelte 5 requires a modern browser (in other words, not Internet Explorer) for various reasons:
- it uses [`Proxies`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy)
- elements with `clientWidth`/`clientHeight`/`offsetWidth`/`offsetHeight` bindings use a [`ResizeObserver`](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver) rather than a convoluted `<iframe>` hack
- `<input type="range" bind:value={...} />` only uses an `input` event listener, rather than also listening for `change` events as a fallback
The `legacy` compiler option, which generated bulkier but IE-friendly code, no longer exists.
## Changes to compiler options
- The `false`/`true` (already deprecated previously) and the `"none"` values were removed as valid values from the `css` option
- The `legacy` option was repurposed
- The `hydratable` option has been removed. Svelte components are always hydratable now
- The `enableSourcemap` option has been removed. Source maps are always generated now, tooling can choose to ignore it
- The `tag` option was removed. Use `<svelte:options customElement="tag-name" />` inside the component instead
- The `loopGuardTimeout`, `format`, `sveltePath`, `errorMode` and `varsReport` options were removed
## The `children` prop is reserved
Content inside component tags becomes a snippet prop called `children`. You cannot have a separate prop by that name.
## Dot notation indicates a component
In Svelte 4, `<foo.bar>` would create an element with a tag name of `"foo.bar"`. In Svelte 5, `foo.bar` is treated as a component instead. This is particularly useful inside `each` blocks:
```svelte
{#each items as item}
<item.component {...item.props} />
{/each}
```
## Breaking changes in runes mode
Some breaking changes only apply once your component is in runes mode.
### Bindings to component exports are not allowed
Exports from runes mode components cannot be bound to directly. For example, having `export const foo = ...` in component `A` and then doing `<A bind:foo />` causes an error. Use `bind:this` instead — `<A bind:this={a} />` — and access the export as `a.foo`. This change makes things easier to reason about, as it enforces a clear separation between props and exports.
### Bindings need to be explicitly defined using `$bindable()`
In Svelte 4 syntax, every property (declared via `export let`) is bindable, meaning you can `bind:` to it. In runes mode, properties are not bindable by default: you need to denote bindable props with the `$bindable` rune.
If a bindable property has a default value (e.g. `let { foo = $bindable('bar') } = $props();`), you need to pass a non-`undefined` value to that property if you're binding to it. This prevents ambiguous behavior — the parent and child must have the same value — and results in better performance (in Svelte 4, the default value was reflected back to the parent, resulting in wasteful additional render cycles).
### `accessors` option is ignored
Setting the `accessors` option to `true` makes properties of a component directly accessible on the component instance. In runes mode, properties are never accessible on the component instance. You can use component exports instead if you need to expose them.
### `immutable` option is ignored
Setting the `immutable` option has no effect in runes mode. This concept is replaced by how `$state` and its variations work.
### Classes are no longer "auto-reactive"
In Svelte 4, doing the following triggered reactivity:
```svelte
<script>
let foo = new Foo();
</script>
<button on:click={() => (foo.value = 1)}>{foo.value}</button
>
```
This is because the Svelte compiler treated the assignment to `foo.value` as an instruction to update anything that referenced `foo`. In Svelte 5, reactivity is determined at runtime rather than compile time, so you should define `value` as a reactive `$state` field on the `Foo` class. Wrapping `new Foo()` with `$state(...)` will have no effect — only vanilla objects and arrays are made deeply reactive.
### `<svelte:component>` is no longer necessary
In Svelte 4, components are _static_ — if you render `<Thing>`, and the value of `Thing` changes, [nothing happens](https://svelte.dev/repl/7f1fa24f0ab44c1089dcbb03568f8dfa?version=4.2.18). To make it dynamic you must use `<svelte:component>`.
This is no longer true in Svelte 5:
```svelte
<script>
import A from './A.svelte';
import B from './B.svelte';
let Thing = $state();
</script>
<select bind:value={Thing}>
<option value={A}>A</option>
<option value={B}>B</option>
</select>
<!-- these are equivalent -->
<Thing />
<svelte:component this={Thing} />
```
### Touch and wheel events are passive
When using `onwheel`, `onmousewheel`, `ontouchstart` and `ontouchmove` event attributes, the handlers are [passive](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#using_passive_listeners) to align with browser defaults. This greatly improves responsiveness by allowing the browser to scroll the document immediately, rather than waiting to see if the event handler calls `event.preventDefault()`.
In the very rare cases that you need to prevent these event defaults, you should use [`on`](/docs/svelte/svelte-events#on) instead (for example inside an action).
### Attribute/prop syntax is stricter
In Svelte 4, complex attribute values needn't be quoted:
<!-- prettier-ignore -->
```svelte
<Component prop=this{is}valid />
```
This is a footgun. In runes mode, if you want to concatenate stuff you must wrap the value in quotes:
```svelte
<Component prop="this{is}valid" />
```
Note that Svelte 5 will also warn if you have a single expression wrapped in quotes, like `answer="{42}"` — in Svelte 6, that will cause the value to be converted to a string, rather than passed as a number.
### HTML structure is stricter
In Svelte 4, you were allowed to write HTML code that would be repaired by the browser when server side rendering it. For example you could write this...
```svelte
<table>
<tr>
<td>hi</td>
</tr>
</table>
```
... and the browser would auto-insert a `<tbody>` element:
```svelte
<table>
<tbody>
<tr>
<td>hi</td>
</tr>
</tbody>
</table>
```
Svelte 5 is more strict about the HTML structure and will throw a compiler error in cases where the browser would repair the DOM.
## Other breaking changes
### Stricter `@const` assignment validation
Assignments to destructured parts of a `@const` declaration are no longer allowed. It was an oversight that this was ever allowed.
### :is(...) and :where(...) are scoped
Previously, Svelte did not analyse selectors inside `:is(...)` and `:where(...)`, effectively treating them as global. Svelte 5 analyses them in the context of the current component. As such, some selectors may now be treated as unused if they were relying on this treatment. To fix this, use `:global(...)` inside the `:is(...)/:where(...)` selectors.
When using Tailwind's `@apply` directive, add a `:global` selector to preserve rules that use Tailwind-generated `:is(...)` selectors:
<!-- prettier-ignore -->
```css
main +++:global+++ {
@apply bg-blue-100 dark:bg-blue-900;
}
```
### CSS hash position no longer deterministic
Previously Svelte would always insert the CSS hash last. This is no longer guaranteed in Svelte 5. This is only breaking if you [have very weird css selectors](https://stackoverflow.com/questions/15670631/does-the-order-of-classes-listed-on-an-item-affect-the-css).
### Scoped CSS uses :where(...)
To avoid issues caused by unpredictable specificity changes, scoped CSS selectors now use `:where(.svelte-xyz123)` selector modifiers alongside `.svelte-xyz123` (where `xyz123` is, as previously, a hash of the `<style>` contents). You can read more detail [here](https://github.com/sveltejs/svelte/pull/10443).
In the event that you need to support ancient browsers that don't implement `:where`, you can manually alter the emitted CSS, at the cost of unpredictable specificity changes:
```js
// @errors: 2552
css = css.replace(/:where\((.+?)\)/, '$1');
```
### Error/warning codes have been renamed
Error and warning codes have been renamed. Previously they used dashes to separate the words, they now use underscores (e.g. foo-bar becomes foo_bar). Additionally, a handful of codes have been reworded slightly.
### Reduced number of namespaces
The number of valid namespaces you can pass to the compiler option `namespace` has been reduced to `html` (the default), `mathml` and `svg`.
The `foreign` namespace was only useful for Svelte Native, which we're planning to support differently in a 5.x minor.
### beforeUpdate/afterUpdate changes
`beforeUpdate` no longer runs twice on initial render if it modifies a variable referenced in the template.
`afterUpdate` callbacks in a parent component will now run after `afterUpdate` callbacks in any child components.
Both functions are disallowed in runes mode — use `$effect.pre(...)` and `$effect(...)` instead.
### `contenteditable` behavior change
If you have a `contenteditable` node with a corresponding binding _and_ a reactive value inside it (example: `<div contenteditable=true bind:textContent>count is {count}</div>`), then the value inside the contenteditable will not be updated by updates to `count` because the binding takes full control over the content immediately and it should only be updated through it.
### `oneventname` attributes no longer accept string values
In Svelte 4, it was possible to specify event attributes on HTML elements as a string:
```svelte
<button onclick="alert('hello')">...</button>
```
This is not recommended, and is no longer possible in Svelte 5, where properties like `onclick` replace `on:click` as the mechanism for adding event handlers.
### `null` and `undefined` become the empty string
In Svelte 4, `null` and `undefined` were printed as the corresponding string. In 99 out of 100 cases you want this to become the empty string instead, which is also what most other frameworks out there do. Therefore, in Svelte 5, `null` and `undefined` become the empty string.
### `bind:files` values can only be `null`, `undefined` or `FileList`
`bind:files` is now a two-way binding. As such, when setting a value, it needs to be either falsy (`null` or `undefined`) or of type `FileList`.
### Bindings now react to form resets
Previously, bindings did not take into account `reset` event of forms, and therefore values could get out of sync with the DOM. Svelte 5 fixes this by placing a `reset` listener on the document and invoking bindings where necessary.
### `walk` not longer exported
`svelte/compiler` reexported `walk` from `estree-walker` for convenience. This is no longer true in Svelte 5, import it directly from that package instead in case you need it.
### Content inside `svelte:options` is forbidden
In Svelte 4 you could have content inside a `<svelte:options />` tag. It was ignored, but you could write something in there. In Svelte 5, content inside that tag is a compiler error.
### `<slot>` elements in declarative shadow roots are preserved
Svelte 4 replaced the `<slot />` tag in all places with its own version of slots. Svelte 5 preserves them in the case they are a child of a `<template shadowrootmode="...">` element.
### `<svelte:element>` tag must be an expression
In Svelte 4, `<svelte:element this="div">` is valid code. This makes little sense — you should just do `<div>`. In the vanishingly rare case that you _do_ need to use a literal value for some reason, you can do this:
```svelte
<svelte:element this=+++{+++"div"+++}+++>
```
Note that whereas Svelte 4 would treat `<svelte:element this="input">` (for example) identically to `<input>` for the purposes of determining which `bind:` directives could be applied, Svelte 5 does not.
### `mount` plays transitions by default
The `mount` function used to render a component tree plays transitions by default unless the `intro` option is set to `false`. This is different from legacy class components which, when manually instantiated, didn't play transitions by default.
### `<img src={...}>` and `{@html ...}` hydration mismatches are not repaired
In Svelte 4, if the value of a `src` attribute or `{@html ...}` tag differ between server and client (a.k.a. a hydration mismatch), the mismatch is repaired. This is very costly: setting a `src` attribute (even if it evaluates to the same thing) causes images and iframes to be reloaded, and reinserting a large blob of HTML is slow.
Since these mismatches are extremely rare, Svelte 5 assumes that the values are unchanged, but in development will warn you if they are not. To force an update you can do something like this:
```svelte
<script>
let { markup, src } = $props();
if (typeof window !== 'undefined') {
// stash the values...
const initial = { markup, src };
// unset them...
markup = src = undefined;
$effect(() => {
// ...and reset after we've mounted
markup = initial.markup;
src = initial.src;
});
}
</script>
{@html markup}
<img {src} />
```
### Hydration works differently
Svelte 5 makes use of comments during server side rendering which are used for more robust and efficient hydration on the client. As such, you shouldn't remove comments from your HTML output if you intend to hydrate it, and if you manually authored HTML to be hydrated by a Svelte component, you need to adjust that HTML to include said comments at the correct positions.
### `onevent` attributes are delegated
Event attributes replace event directives: Instead of `on:click={handler}` you write `onclick={handler}`. For backwards compatibility the `on:event` syntax is still supported and behaves the same as in Svelte 4. Some of the `onevent` attributes however are delegated, which means you need to take care to not stop event propagation on those manually, as they then might never reach the listener for this event type at the root.
### `--style-props` uses a different element
Svelte 5 uses an extra `<svelte-css-wrapper>` element instead of a `<div>` to wrap the component when using CSS custom properties.
<!-- TODO in final docs, add link to corresponding section for more details -->

@ -1,9 +0,0 @@
---
title: $state
---
TODO
- add other pages
- figure out a way to get separator titles in here, so we can have a 'runes' section and an 'imports' section and an 'errors/warnings' section without introducing another layer of nesting
- figure out a good way to import reference docs from other repos that works locally and in prod

@ -7,7 +7,7 @@ This tutorial is designed to get you familiar with the process of writing compon
First, you'll need to integrate Svelte with a build tool. We recommend using [SvelteKit](https://kit.svelte.dev), which sets up [Vite](https://vitejs.dev/) with [vite-plugin-svelte](https://github.com/sveltejs/vite-plugin-svelte/) for you...
```bash
npm create svelte@latest myapp
npx sv create myapp
```
There are also a number of [community-maintained integrations](https://sveltesociety.dev/tools).

@ -15,7 +15,7 @@ You can play around with Svelte in the [tutorial](https://learn.svelte.dev/), [e
When you're ready to build a full-fledge application, we recommend using [SvelteKit](https://kit.svelte.dev):
```bash
npm create svelte@latest my-app
npx sv create my-app
cd my-app
npm install
npm run dev

@ -133,7 +133,7 @@ npm install svelte@next
You can also opt into Svelte 5 when creating a new SvelteKit project:
```bash
npm create svelte@latest
npx sv create
```
### What's left to do?

Loading…
Cancel
Save