More docs stuff (#13769)

* fix

* link

* more docs stuff

* more

* more

* fix

* more

* more

* fix

* fix

* more

* ffs

* FML
transition-out-effect-tracking
Rich Harris 2 weeks ago committed by GitHub
parent 4c7cfff434
commit 4f6bb41030
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -66,4 +66,4 @@ CSS inside a `<style>` block will be scoped to that component.
</style>
```
For more information regarding styling, read the documentation around [styles and classes](styles-and-classes).
For more information, head to the section on [styling](scoped-styles).

@ -95,7 +95,7 @@ $effect(() => {
});
```
An effect only reruns when the object it reads changes, not when a property inside it changes. (If you want to observe changes _inside_ an object at dev time, you can use [`$inspect`](debugging#$inspect).)
An effect only reruns when the object it reads changes, not when a property inside it changes. (If you want to observe changes _inside_ an object at dev time, you can use [`$inspect`]($inspect).)
```svelte
<script>

@ -22,7 +22,7 @@ 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:
Content rendered this way is 'invisible' to Svelte and as such will not receive [scoped styles](scoped-styles) — in other words, this will not work, and the `a` and `img` styles will be regarded as unused:
<!-- prettier-ignore -->
```svelte

@ -1,28 +1,7 @@
---
title: Debugging
title: {@debug ...}
---
- `@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
@ -53,3 +32,4 @@ The `{@debug ...}` tag offers an alternative to `console.log(...)`. It logs the
```
The `{@debug}` tag without any arguments will insert a `debugger` statement that gets triggered when _any_ state changes, as opposed to the specified variables.

@ -249,14 +249,14 @@ To get a reference to a DOM node, use `bind:this`. The value will be `undefined`
Components also support `bind:this`, allowing you to interact with component instances programmatically.
```svelte
<!--- App.svelte --->
<!--- file: App.svelte --->
<ShoppingCart bind:this={cart} />
<button onclick={() => cart.empty()}> Empty shopping cart </button>
```
```svelte
<!--- ShoppingCart.svelte --->
<!--- file: ShoppingCart.svelte --->
<script>
// All instance exports are available on the instance object
export function empty() {
@ -279,7 +279,7 @@ You can bind to component props using the same syntax as for elements.
While Svelte props are reactive without binding, that reactivity only flows downward into the component by default. Using `bind:property` allows changes to the property from within the component to flow back up out of the component.
To mark a property as bindable, use the `$bindable` rune:
To mark a property as bindable, use the [`$bindable`]($bindable) rune:
```svelte
<script>

@ -1,103 +0,0 @@
---
title: use:
---
- template syntax
- how to write
- typings
- adjust so that `$effect` is used instead of update/destroy?
```svelte
<!--- copy: false --->
use:action
```
```svelte
<!--- copy: false --->
use:action={parameters}
```
```ts
/// copy: false
// @noErrors
action = (node: HTMLElement, parameters: any) => {
update?: (parameters: any) => void,
destroy?: () => void
}
```
Actions are functions that are called when an element is created. They can return an object with a `destroy` method that is called after the element is unmounted:
```svelte
<!--- file: App.svelte --->
<script>
/** @type {import('svelte/action').Action} */
function foo(node) {
// the node has been mounted in the DOM
return {
destroy() {
// the node has been removed from the DOM
}
};
}
</script>
<div use:foo />
```
An action can have a parameter. If the returned value has an `update` method, it will be called immediately after Svelte has applied updates to the markup whenever that parameter changes.
> [!NOTE] Don't worry that we're redeclaring the `foo` function for every component instance — Svelte will hoist any functions that don't depend on local state out of the component definition.
```svelte
<!--- file: App.svelte --->
<script>
/** @type {string} */
export let bar;
/** @type {import('svelte/action').Action<HTMLElement, string>} */
function foo(node, bar) {
// the node has been mounted in the DOM
return {
update(bar) {
// the value of `bar` has changed
},
destroy() {
// the node has been removed from the DOM
}
};
}
</script>
<div use:foo={bar} />
```
## Attributes
Sometimes actions emit custom events and apply custom attributes to the element they are applied to. To support this, actions typed with `Action` or `ActionReturn` type can have a last parameter, `Attributes`:
```svelte
<!--- file: App.svelte --->
<script>
/**
* @type {import('svelte/action').Action<HTMLDivElement, { prop: any }, { 'on:emit': (e: CustomEvent<string>) => void }>}
*/
function foo(node, { prop }) {
// the node has been mounted in the DOM
//...LOGIC
node.dispatchEvent(new CustomEvent('emit', { detail: 'hello' }));
return {
destroy() {
// the node has been removed from the DOM
}
};
}
</script>
<div use:foo={{ prop: 'someValue' }} onemit={handleEmit} />
```

@ -1,410 +0,0 @@
---
title: transition:
---
- how to use (template syntax)
- when to use
- global vs local
- easing & motion
- mention imports
- key block
Svelte provides different techniques and syntax for incorporating motion into your Svelte projects.
## transition:_fn_
```svelte
<!--- copy: false --->
transition:fn
```
```svelte
<!--- copy: false --->
transition:fn={params}
```
```svelte
<!--- copy: false --->
transition:fn|global
```
```svelte
<!--- copy: false --->
transition:fn|global={params}
```
```svelte
<!--- copy: false --->
transition:fn|local
```
```svelte
<!--- copy: false --->
transition:fn|local={params}
```
```js
/// copy: false
// @noErrors
transition = (node: HTMLElement, params: any, options: { direction: 'in' | 'out' | 'both' }) => {
delay?: number,
duration?: number,
easing?: (t: number) => number,
css?: (t: number, u: number) => string,
tick?: (t: number, u: number) => void
}
```
A transition is triggered by an element entering or leaving the DOM as a result of a state change.
When a block is transitioning out, all elements inside the block, including those that do not have their own transitions, are kept in the DOM until every transition in the block has been completed.
The `transition:` directive indicates a _bidirectional_ transition, which means it can be smoothly reversed while the transition is in progress.
```svelte
{#if visible}
<div transition:fade>fades in and out</div>
{/if}
```
Transitions are local by default. Local transitions only play when the block they belong to is created or destroyed, _not_ when parent blocks are created or destroyed.
```svelte
{#if x}
{#if y}
<p transition:fade>fades in and out only when y changes</p>
<p transition:fade|global>fades in and out when x or y change</p>
{/if}
{/if}
```
> [!NOTE] By default intro transitions will not play on first render. You can modify this behaviour by setting `intro: true` when you [create a component](imperative-component-api) and marking the transition as `global`.
## Transition parameters
Transitions can have parameters.
(The double `{{curlies}}` aren't a special syntax; this is an object literal inside an expression tag.)
```svelte
{#if visible}
<div transition:fade={{ duration: 2000 }}>fades in and out over two seconds</div>
{/if}
```
## Custom transition functions
Transitions can use custom functions. If the returned object has a `css` function, Svelte will create a CSS animation that plays on the element.
The `t` argument passed to `css` is a value between `0` and `1` after the `easing` function has been applied. _In_ transitions run from `0` to `1`, _out_ transitions run from `1` to `0` in other words, `1` is the element's natural state, as though no transition had been applied. The `u` argument is equal to `1 - t`.
The function is called repeatedly _before_ the transition begins, with different `t` and `u` arguments.
```svelte
<!--- file: App.svelte --->
<script>
import { elasticOut } from 'svelte/easing';
/** @type {boolean} */
export let visible;
/**
* @param {HTMLElement} node
* @param {{ delay?: number, duration?: number, easing?: (t: number) => number }} params
*/
function whoosh(node, params) {
const existingTransform = getComputedStyle(node).transform.replace('none', '');
return {
delay: params.delay || 0,
duration: params.duration || 400,
easing: params.easing || elasticOut,
css: (t, u) => `transform: ${existingTransform} scale(${t})`
};
}
</script>
{#if visible}
<div in:whoosh>whooshes in</div>
{/if}
```
A custom transition function can also return a `tick` function, which is called _during_ the transition with the same `t` and `u` arguments.
> [!NOTE] If it's possible to use `css` instead of `tick`, do so — CSS animations can run off the main thread, preventing jank on slower devices.
```svelte
<!--- file: App.svelte --->
<script>
export let visible = false;
/**
* @param {HTMLElement} node
* @param {{ speed?: number }} params
*/
function typewriter(node, { speed = 1 }) {
const valid = node.childNodes.length === 1 && node.childNodes[0].nodeType === Node.TEXT_NODE;
if (!valid) {
throw new Error(`This transition only works on elements with a single text node child`);
}
const text = node.textContent;
const duration = text.length / (speed * 0.01);
return {
duration,
tick: (t) => {
const i = ~~(text.length * t);
node.textContent = text.slice(0, i);
}
};
}
</script>
{#if visible}
<p in:typewriter={{ speed: 1 }}>The quick brown fox jumps over the lazy dog</p>
{/if}
```
If a transition returns a function instead of a transition object, the function will be called in the next microtask. This allows multiple transitions to coordinate, making [crossfade effects](/tutorial/deferred-transitions) possible.
Transition functions also receive a third argument, `options`, which contains information about the transition.
Available values in the `options` object are:
- `direction` - one of `in`, `out`, or `both` depending on the type of transition
## Transition events
An element with transitions will dispatch the following events in addition to any standard DOM events:
- `introstart`
- `introend`
- `outrostart`
- `outroend`
```svelte
{#if visible}
<p
transition:fly={{ y: 200, duration: 2000 }}
on:introstart={() => (status = 'intro started')}
on:outrostart={() => (status = 'outro started')}
on:introend={() => (status = 'intro ended')}
on:outroend={() => (status = 'outro ended')}
>
Flies in and out
</p>
{/if}
```
## in:_fn_/out:_fn_
```svelte
<!--- copy: false --->
in:fn
```
```svelte
<!--- copy: false --->
in:fn={params}
```
```svelte
<!--- copy: false --->
in:fn|global
```
```svelte
<!--- copy: false --->
in:fn|global={params}
```
```svelte
<!--- copy: false --->
in:fn|local
```
```svelte
<!--- copy: false --->
in:fn|local={params}
```
```svelte
<!--- copy: false --->
out:fn
```
```svelte
<!--- copy: false --->
out:fn={params}
```
```svelte
<!--- copy: false --->
out:fn|global
```
```svelte
<!--- copy: false --->
out:fn|global={params}
```
```svelte
<!--- copy: false --->
out:fn|local
```
```svelte
<!--- copy: false --->
out:fn|local={params}
```
Similar to `transition:`, but only applies to elements entering (`in:`) or leaving (`out:`) the DOM.
Unlike with `transition:`, transitions applied with `in:` and `out:` are not bidirectional — an in transition will continue to 'play' alongside the out transition, rather than reversing, if the block is outroed while the transition is in progress. If an out transition is aborted, transitions will restart from scratch.
```svelte
{#if visible}
<div in:fly out:fade>flies in, fades out</div>
{/if}
```
## animate:_fn_
```svelte
<!--- copy: false --->
animate:name
```
```svelte
<!--- copy: false --->
animate:name={params}
```
```js
/// copy: false
// @noErrors
animation = (node: HTMLElement, { from: DOMRect, to: DOMRect } , params: any) => {
delay?: number,
duration?: number,
easing?: (t: number) => number,
css?: (t: number, u: number) => string,
tick?: (t: number, u: number) => void
}
```
```ts
/// copy: false
// @noErrors
DOMRect {
bottom: number,
height: number,
left: number,
right: number,
top: number,
width: number,
x: number,
y: number
}
```
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).
```svelte
<!-- When `list` is reordered the animation will run-->
{#each list as item, index (item)}
<li animate:flip>{item}</li>
{/each}
```
## Animation Parameters
As with actions and transitions, animations can have parameters.
(The double `{{curlies}}` aren't a special syntax; this is an object literal inside an expression tag.)
```svelte
{#each list as item, index (item)}
<li animate:flip={{ delay: 500 }}>{item}</li>
{/each}
```
## Custom animation functions
Animations can use custom functions that provide the `node`, an `animation` object and any `parameters` as arguments. The `animation` parameter is an object containing `from` and `to` properties each containing a [DOMRect](https://developer.mozilla.org/en-US/docs/Web/API/DOMRect#Properties) describing the geometry of the element in its `start` and `end` positions. The `from` property is the DOMRect of the element in its starting position, and the `to` property is the DOMRect of the element in its final position after the list has been reordered and the DOM updated.
If the returned object has a `css` method, Svelte will create a CSS animation that plays on the element.
The `t` argument passed to `css` is a value that goes from `0` and `1` after the `easing` function has been applied. The `u` argument is equal to `1 - t`.
The function is called repeatedly _before_ the animation begins, with different `t` and `u` arguments.
<!-- TODO: Types -->
```svelte
<!--- file: App.svelte --->
<script>
import { cubicOut } from 'svelte/easing';
/**
* @param {HTMLElement} node
* @param {{ from: DOMRect; to: DOMRect }} states
* @param {any} params
*/
function whizz(node, { from, to }, params) {
const dx = from.left - to.left;
const dy = from.top - to.top;
const d = Math.sqrt(dx * dx + dy * dy);
return {
delay: 0,
duration: Math.sqrt(d) * 120,
easing: cubicOut,
css: (t, u) => `transform: translate(${u * dx}px, ${u * dy}px) rotate(${t * 360}deg);`
};
}
</script>
{#each list as item, index (item)}
<div animate:whizz>{item}</div>
{/each}
```
A custom animation function can also return a `tick` function, which is called _during_ the animation with the same `t` and `u` arguments.
> [!NOTE] If it's possible to use `css` instead of `tick`, do so — CSS animations can run off the main thread, preventing jank on slower devices.
```svelte
<!--- file: App.svelte --->
<script>
import { cubicOut } from 'svelte/easing';
/**
* @param {HTMLElement} node
* @param {{ from: DOMRect; to: DOMRect }} states
* @param {any} params
*/
function whizz(node, { from, to }, params) {
const dx = from.left - to.left;
const dy = from.top - to.top;
const d = Math.sqrt(dx * dx + dy * dy);
return {
delay: 0,
duration: Math.sqrt(d) * 120,
easing: cubicOut,
tick: (t, u) => Object.assign(node.style, { color: t > 0.5 ? 'Pink' : 'Blue' })
};
}
</script>
{#each list as item, index (item)}
<div animate:whizz>{item}</div>
{/each}
```

@ -0,0 +1,81 @@
---
title: use:
---
Actions are functions that are called when an element is mounted. They are added with the `use:` directive, and will typically use an `$effect` so that they can reset any state when the element is unmounted:
```svelte
<!--- file: App.svelte --->
<script>
/** @type {import('svelte/action').Action} */
function myaction(node) {
// the node has been mounted in the DOM
$effect(() => {
// setup goes here
return () => {
// teardown goes here
};
});
}
</script>
<div use:myaction>...</div>
```
An action can be called with an argument:
```svelte
<!--- file: App.svelte --->
<script>
/** @type {import('svelte/action').Action} */
function myaction(node, +++data+++) {
// ...
}
</script>
<div use:myaction={+++data+++}>...</div>
```
The action is only called once (but not during server-side rendering) — it will _not_ run again if the argument changes.
> [!LEGACY]
> Prior to the `$effect` rune, actions could return an object with `update` and `destroy` methods, where `update` would be called with the latest value of the argument if it changed. Using effects is preferred.
## Typing
The `Action` interface receives three optional type arguments — a node type (which can be `Element`, if the action applies to everything), a parameter, and any custom event handlers created by the action.:
```svelte
<!--- file: App.svelte --->
<script>
import { on } from 'svelte/events';
/**
* @type {import('svelte/action').Action<
* HTMLDivElement,
* null,
* {
* onswiperight: (e: CustomEvent) => void;
* onswipeleft: (e: CustomEvent) => void;
* // ...
* }>}
*/
function gestures(node) {
$effect(() => {
// ...
node.dispatchEvent(new CustomEvent('swipeleft'));
// ...
node.dispatchEvent(new CustomEvent('swiperight'));
});
}
</script>
<div
use:gestures
onswipeleft={next}
onswiperight={prev}
>...</div>
```

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

@ -0,0 +1,172 @@
---
title: transition:
---
A _transition_ is triggered by an element entering or leaving the DOM as a result of a state change.
When a block (such as an `{#if ...}` block) is transitioning out, all elements inside it, including those that do not have their own transitions, are kept in the DOM until every transition in the block has been completed.
The `transition:` directive indicates a _bidirectional_ transition, which means it can be smoothly reversed while the transition is in progress.
```svelte
<script>
+++import { fade } from 'svelte/transition';+++
let visible = $state(false);
</script>
<button onclick={() => visible = !visible}>toggle</button>
{#if visible}
<div +++transition:fade+++>fades in and out</div>
{/if}
```
## Built-in transitions
A selection of built-in transitions can be imported from the [`svelte/transition`](svelte-transition) module.
## Local vs global
Transitions are local by default. Local transitions only play when the block they belong to is created or destroyed, _not_ when parent blocks are created or destroyed.
```svelte
{#if x}
{#if y}
<p transition:fade>fades in and out only when y changes</p>
<p transition:fade|global>fades in and out when x or y change</p>
{/if}
{/if}
```
## Transition parameters
Transitions can have parameters.
(The double `{{curlies}}` aren't a special syntax; this is an object literal inside an expression tag.)
```svelte
{#if visible}
<div transition:fade={{ duration: 2000 }}>fades in and out over two seconds</div>
{/if}
```
## Custom transition functions
```js
/// copy: false
// @noErrors
transition = (node: HTMLElement, params: any, options: { direction: 'in' | 'out' | 'both' }) => {
delay?: number,
duration?: number,
easing?: (t: number) => number,
css?: (t: number, u: number) => string,
tick?: (t: number, u: number) => void
}
```
Transitions can use custom functions. If the returned object has a `css` function, Svelte will generate keyframes for a [web animation](https://developer.mozilla.org/en-US/docs/Web/API/Web_Animations_API).
The `t` argument passed to `css` is a value between `0` and `1` after the `easing` function has been applied. _In_ transitions run from `0` to `1`, _out_ transitions run from `1` to `0` in other words, `1` is the element's natural state, as though no transition had been applied. The `u` argument is equal to `1 - t`.
The function is called repeatedly _before_ the transition begins, with different `t` and `u` arguments.
```svelte
<!--- file: App.svelte --->
<script>
import { elasticOut } from 'svelte/easing';
/** @type {boolean} */
export let visible;
/**
* @param {HTMLElement} node
* @param {{ delay?: number, duration?: number, easing?: (t: number) => number }} params
*/
function whoosh(node, params) {
const existingTransform = getComputedStyle(node).transform.replace('none', '');
return {
delay: params.delay || 0,
duration: params.duration || 400,
easing: params.easing || elasticOut,
css: (t, u) => `transform: ${existingTransform} scale(${t})`
};
}
</script>
{#if visible}
<div in:whoosh>whooshes in</div>
{/if}
```
A custom transition function can also return a `tick` function, which is called _during_ the transition with the same `t` and `u` arguments.
> [!NOTE] If it's possible to use `css` instead of `tick`, do so — web animations can run off the main thread, preventing jank on slower devices.
```svelte
<!--- file: App.svelte --->
<script>
export let visible = false;
/**
* @param {HTMLElement} node
* @param {{ speed?: number }} params
*/
function typewriter(node, { speed = 1 }) {
const valid = node.childNodes.length === 1 && node.childNodes[0].nodeType === Node.TEXT_NODE;
if (!valid) {
throw new Error(`This transition only works on elements with a single text node child`);
}
const text = node.textContent;
const duration = text.length / (speed * 0.01);
return {
duration,
tick: (t) => {
const i = ~~(text.length * t);
node.textContent = text.slice(0, i);
}
};
}
</script>
{#if visible}
<p in:typewriter={{ speed: 1 }}>The quick brown fox jumps over the lazy dog</p>
{/if}
```
If a transition returns a function instead of a transition object, the function will be called in the next microtask. This allows multiple transitions to coordinate, making [crossfade effects](/tutorial/deferred-transitions) possible.
Transition functions also receive a third argument, `options`, which contains information about the transition.
Available values in the `options` object are:
- `direction` - one of `in`, `out`, or `both` depending on the type of transition
## Transition events
An element with transitions will dispatch the following events in addition to any standard DOM events:
- `introstart`
- `introend`
- `outrostart`
- `outroend`
```svelte
{#if visible}
<p
transition:fly={{ y: 200, duration: 2000 }}
onintrostart={() => (status = 'intro started')}
onoutrostart={() => (status = 'outro started')}
onintroend={() => (status = 'intro ended')}
onoutroend={() => (status = 'outro ended')}
>
Flies in and out
</p>
{/if}
```

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

@ -0,0 +1,11 @@
---
title: in: and out:
---
The `in:` and `out:` directives are identical to [`transition:`](transition), except that the resulting transitions are not bidirectional — an `in` transition will continue to 'play' alongside the `out` transition, rather than reversing, if the block is outroed while the transition is in progress. If an out transition is aborted, transitions will restart from scratch.
```svelte
{#if visible}
<div in:fly out:fade>flies in, fades out</div>
{/if}
```

@ -0,0 +1,118 @@
---
title: animate:
---
An animation is triggered when the contents of a [keyed each block](each#Keyed-each-blocks) 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).
```svelte
<!-- When `list` is reordered the animation will run-->
{#each list as item, index (item)}
<li animate:flip>{item}</li>
{/each}
```
## Animation Parameters
As with actions and transitions, animations can have parameters.
(The double `{{curlies}}` aren't a special syntax; this is an object literal inside an expression tag.)
```svelte
{#each list as item, index (item)}
<li animate:flip={{ delay: 500 }}>{item}</li>
{/each}
```
## Custom animation functions
```js
/// copy: false
// @noErrors
animation = (node: HTMLElement, { from: DOMRect, to: DOMRect } , params: any) => {
delay?: number,
duration?: number,
easing?: (t: number) => number,
css?: (t: number, u: number) => string,
tick?: (t: number, u: number) => void
}
```
Animations can use custom functions that provide the `node`, an `animation` object and any `parameters` as arguments. The `animation` parameter is an object containing `from` and `to` properties each containing a [DOMRect](https://developer.mozilla.org/en-US/docs/Web/API/DOMRect#Properties) describing the geometry of the element in its `start` and `end` positions. The `from` property is the DOMRect of the element in its starting position, and the `to` property is the DOMRect of the element in its final position after the list has been reordered and the DOM updated.
If the returned object has a `css` method, Svelte will create a [web animation](https://developer.mozilla.org/en-US/docs/Web/API/Web_Animations_API) that plays on the element.
The `t` argument passed to `css` is a value that goes from `0` and `1` after the `easing` function has been applied. The `u` argument is equal to `1 - t`.
The function is called repeatedly _before_ the animation begins, with different `t` and `u` arguments.
<!-- TODO: Types -->
```svelte
<!--- file: App.svelte --->
<script>
import { cubicOut } from 'svelte/easing';
/**
* @param {HTMLElement} node
* @param {{ from: DOMRect; to: DOMRect }} states
* @param {any} params
*/
function whizz(node, { from, to }, params) {
const dx = from.left - to.left;
const dy = from.top - to.top;
const d = Math.sqrt(dx * dx + dy * dy);
return {
delay: 0,
duration: Math.sqrt(d) * 120,
easing: cubicOut,
css: (t, u) => `transform: translate(${u * dx}px, ${u * dy}px) rotate(${t * 360}deg);`
};
}
</script>
{#each list as item, index (item)}
<div animate:whizz>{item}</div>
{/each}
```
A custom animation function can also return a `tick` function, which is called _during_ the animation with the same `t` and `u` arguments.
> [!NOTE] If it's possible to use `css` instead of `tick`, do so — web animations can run off the main thread, preventing jank on slower devices.
```svelte
<!--- file: App.svelte --->
<script>
import { cubicOut } from 'svelte/easing';
/**
* @param {HTMLElement} node
* @param {{ from: DOMRect; to: DOMRect }} states
* @param {any} params
*/
function whizz(node, { from, to }, params) {
const dx = from.left - to.left;
const dy = from.top - to.top;
const d = Math.sqrt(dx * dx + dy * dy);
return {
delay: 0,
duration: Math.sqrt(d) * 120,
easing: cubicOut,
tick: (t, u) => Object.assign(node.style, { color: t > 0.5 ? 'Pink' : 'Blue' })
};
}
</script>
{#each list as item, index (item)}
<div animate:whizz>{item}</div>
{/each}
```

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

@ -0,0 +1,23 @@
---
title: class:
---
The `class:` directive is a convenient way to conditionally set classes on elements, as an alternative to using conditional expressions inside `class` attributes:
```svelte
<!-- These are equivalent -->
<div class={isCool ? 'cool' : ''}>...</div>
<div class:cool={isCool}>...</div>
```
As with other directives, we can use a shorthand when the name of the class coincides with the value:
```svelte
<div class:cool>...</div>
```
Multiple `class:` directives can be added to a single element:
```svelte
<div class:cool class:lame={!cool} class:potato>...</div>
```

@ -0,0 +1,41 @@
---
title: style:
---
The `style:` directive provides a shorthand for setting multiple styles on an element.
```svelte
<!-- These are equivalent -->
<div style:color="red">...</div>
<div style="color: red;">...</div>
```
The value can contain arbitrary expressions:
```svelte
<div style:color={myColor}>...</div>
```
The shorthand form is allowed:
```svelte
<div style:color>...</div>
```
Multiple styles can be set on a single element:
```svelte
<div style:color style:width="12rem" style:background-color={darkMode ? 'black' : 'white'}>...</div>
```
To mark a style as important, use the `|important` modifier:
```svelte
<div style:color|important="red">...</div>
```
When `style:` directives are combined with `style` attributes, the directives will take precedence:
```svelte
<div style="color: blue;" style:color="red">This will be red</div>
```

@ -0,0 +1,42 @@
---
title: Scoped styles
---
Svelte components can include a `<style>` element containing CSS that belongs to the component. This CSS is _scoped_ by default, meaning that styles will not apply to any elements on the page outside the component in question.
This works by adding a class to affected elements, which is based on a hash of the component styles (e.g. `svelte-123xyz`).
```svelte
<style>
p {
/* this will only affect <p> elements in this component */
color: burlywood;
}
</style>
```
## Specificity
Each scoped selector receives a [specificity](https://developer.mozilla.org/en-US/docs/Web/CSS/Specificity) increase of 0-1-0, as a result of the scoping class (e.g. `.svelte-123xyz`) being added to the selector. This means that (for example) a `p` selector defined in a component will take precedence over a `p` selector defined in a global stylesheet, even if the global stylesheet is loaded later.
In some cases, the scoping class must be added to a selector multiple times, but after the first occurrence it is added with `:where(.svelte-xyz123)` in order to not increase specificity further.
## Scoped keyframes
If a component defines `@keyframes`, the name is scoped to the component using the same hashing approach. Any `animation` rules in the component will be similarly adjusted:
```svelte
<style>
.bouncy {
animation: bounce 10s;
}
/* these keyframes are only accessible inside this component */
@keyframes bounce {
/* ... *.
}
</style>
```

@ -1,235 +0,0 @@
---
title: Styles & Classes
---
- style scoping
- `:global`
- `style:`
- `class:`
- `--css` props
Styling is a fundamental part of UI components. Svelte helps you style your components with ease, providing useful features out of the box.
## Scoped by default
By default CSS inside a `<style>` block will be scoped to that component.
This works by adding a class to affected elements, which is based on a hash of the component styles (e.g. `svelte-123xyz`).
```svelte
<style>
p {
/* this will only affect <p> elements in this component */
color: burlywood;
}
</style>
```
## :global(...)
To apply styles to a single selector globally, use the `:global(...)` modifier:
```svelte
<style>
:global(body) {
/* applies to <body> */
margin: 0;
}
div :global(strong) {
/* applies to all <strong> elements, in any component,
that are inside <div> elements belonging
to this component */
color: goldenrod;
}
p:global(.big.red) {
/* applies to all <p> elements belonging to this component
with `class="big red"`, even if it is applied
programmatically (for example by a library) */
}
</style>
```
If you want to make @keyframes that are accessible globally, you need to prepend your keyframe names with `-global-`.
The `-global-` part will be removed when compiled, and the keyframe will then be referenced using just `my-animation-name` elsewhere in your code.
```svelte
<style>
@keyframes -global-my-animation-name {
/* code goes here */
}
</style>
```
## :global
To apply styles to a group of selectors globally, create a `:global {...}` block:
```svelte
<style>
:global {
/* applies to every <div> in your application */
div { ... }
/* applies to every <p> in your application */
p { ... }
}
.a :global {
/* applies to every `.b .c .d` element, in any component,
that is inside an `.a` element in this component */
.b .c .d {...}
}
</style>
```
> [!NOTE] The second example above could also be written as an equivalent `.a :global .b .c .d` selector, where everything after the `:global` is unscoped, though the nested form is preferred.
## Nested style tags
There should only be 1 top-level `<style>` tag per component.
However, it is possible to have a `<style>` tag nested inside other elements or logic blocks.
In that case, the `<style>` tag will be inserted as-is into the DOM; no scoping or processing will be done on the `<style>` tag.
```svelte
<div>
<style>
/* this style tag will be inserted as-is */
div {
/* this will apply to all `<div>` elements in the DOM */
color: red;
}
</style>
</div>
```
## class:_name_
```svelte
<!--- copy: false --->
class:name={value}
```
```svelte
<!--- copy: false --->
class:name
```
A `class:` directive provides a shorter way of toggling a class on an element.
```svelte
<!-- These are equivalent -->
<div class={isActive ? 'active' : ''}>...</div>
<div class:active={isActive}>...</div>
<!-- Shorthand, for when name and value match -->
<div class:active>...</div>
<!-- Multiple class toggles can be included -->
<div class:active class:inactive={!active} class:isAdmin>...</div>
```
## style:_property_
```svelte
<!--- copy: false --->
style:property={value}
```
```svelte
<!--- copy: false --->
style:property="value"
```
```svelte
<!--- copy: false --->
style:property
```
The `style:` directive provides a shorthand for setting multiple styles on an element.
```svelte
<!-- These are equivalent -->
<div style:color="red">...</div>
<div style="color: red;">...</div>
<!-- Variables can be used -->
<div style:color={myColor}>...</div>
<!-- Shorthand, for when property and variable name match -->
<div style:color>...</div>
<!-- Multiple styles can be included -->
<div style:color style:width="12rem" style:background-color={darkMode ? 'black' : 'white'}>...</div>
<!-- Styles can be marked as important -->
<div style:color|important="red">...</div>
```
When `style:` directives are combined with `style` attributes, the directives will take precedence:
```svelte
<div style="color: blue;" style:color="red">This will be red</div>
```
## --style-props
```svelte
<!--- copy: false --->
--style-props="anycssvalue"
```
You can also pass styles as props to components for the purposes of theming, using CSS custom properties.
Svelte's implementation is essentially syntactic sugar for adding a wrapper element. This example:
```svelte
<Slider bind:value min={0} --rail-color="black" --track-color="rgb(0, 0, 255)" />
```
Desugars to this:
```svelte
<svelte-css-wrapper style="display: contents; --rail-color: black; --track-color: rgb(0, 0, 255)">
<Slider bind:value min={0} max={100} />
</svelte-css-wrapper>
```
For SVG namespace, the example above desugars into using `<g>` instead:
```svelte
<g style="--rail-color: black; --track-color: rgb(0, 0, 255)">
<Slider bind:value min={0} max={100} />
</g>
```
> [!NOTE] Since this is an extra `<svelte-css-wrapper>` (or `<g>`), beware that your CSS structure might accidentally target this. Be mindful of this added wrapper element when using this feature.
Svelte's CSS Variables support allows for easily themeable components:
```svelte
<style>
.potato-slider-rail {
background-color: var(--rail-color, var(--theme-color, 'purple'));
}
</style>
```
So you can set a high-level theme color:
```css
/* global.css */
html {
--theme-color: black;
}
```
Or override it at the consumer level:
```svelte
<Slider --rail-color="goldenrod" />
```

@ -0,0 +1,65 @@
---
title: Global styles
---
## :global(...)
To apply styles to a single selector globally, use the `:global(...)` modifier:
```svelte
<style>
:global(body) {
/* applies to <body> */
margin: 0;
}
div :global(strong) {
/* applies to all <strong> elements, in any component,
that are inside <div> elements belonging
to this component */
color: goldenrod;
}
p:global(.big.red) {
/* applies to all <p> elements belonging to this component
with `class="big red"`, even if it is applied
programmatically (for example by a library) */
}
</style>
```
If you want to make @keyframes that are accessible globally, you need to prepend your keyframe names with `-global-`.
The `-global-` part will be removed when compiled, and the keyframe will then be referenced using just `my-animation-name` elsewhere in your code.
```svelte
<style>
@keyframes -global-my-animation-name {
/* code goes here */
}
</style>
```
## :global
To apply styles to a group of selectors globally, create a `:global {...}` block:
```svelte
<style>
:global {
/* applies to every <div> in your application */
div { ... }
/* applies to every <p> in your application */
p { ... }
}
.a :global {
/* applies to every `.b .c .d` element, in any component,
that is inside an `.a` element in this component */
.b .c .d {...}
}
</style>
```
> [!NOTE] The second example above could also be written as an equivalent `.a :global .b .c .d` selector, where everything after the `:global` is unscoped, though the nested form is preferred.

@ -0,0 +1,57 @@
---
title: Custom properties
---
You can pass CSS custom properties — both static and dynamic — to components:
```svelte
<Slider
bind:value
min={0}
max={100}
--track-color="black"
--thumb-color="rgb({r} {g} {b})"
/>
```
The above code essentially desugars to this:
```svelte
<svelte-css-wrapper style="display: contents; --track-color: black; --thumb-color: rgb({r} {g} {b})">
<Slider
bind:value
min={0}
max={100}
/>
</svelte-css-wrapper>
```
For an SVG element, it would use `<g>` instead:
```svelte
<g style="--track-color: black; --thumb-color: rgb({r} {g} {b})">
<Slider
bind:value
min={0}
max={100}
/>
</g>
```
Inside the component, we can read these custom properties (and provide fallback values) using [`var(...)`](https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties):
```svelte
<style>
.track {
background: var(--track-color, #aaa);
}
.thumb {
background: var(--thumb-color, blue);
}
</style>
```
You don't _have_ to specify the values directly on the component; as long as the custom properties are defined on a parent element, the component can use them. It's common to define custom properties on the `:root` element in a global stylesheet so that they apply to your entire application.
> [!NOTE] While the extra element will not affect layout, it _will_ affect any CSS selectors that (for example) use the `>` combinator to target an element directly inside the component's container.

@ -0,0 +1,21 @@
---
title: Nested <style> elements
---
There should only be 1 top-level `<style>` tag per component.
However, it is possible to have a `<style>` tag nested inside other elements or logic blocks.
In that case, the `<style>` tag will be inserted as-is into the DOM; no scoping or processing will be done on the `<style>` tag.
```svelte
<div>
<style>
/* this style tag will be inserted as-is */
div {
/* this will apply to all `<div>` elements in the DOM */
color: red;
}
</style>
</div>
```

@ -0,0 +1,44 @@
---
title: <svelte:window>
---
```svelte
<svelte:window onevent={handler} />
```
```svelte
<svelte:window bind:prop={value} />
```
The `<svelte:window>` element allows you to add event listeners to the `window` object without worrying about removing them when the component is destroyed, or checking for the existence of `window` when server-side rendering.
This element may only appear at the top level of your component — it cannot be inside a block or element.
```svelte
<script>
function handleKeydown(event) {
alert(`pressed the ${event.key} key`);
}
</script>
<svelte:window onkeydown={handleKeydown} />
```
You can also bind to the following properties:
- `innerWidth`
- `innerHeight`
- `outerWidth`
- `outerHeight`
- `scrollX`
- `scrollY`
- `online` — an alias for `window.navigator.onLine`
- `devicePixelRatio`
All except `scrollX` and `scrollY` are readonly.
```svelte
<svelte:window bind:scrollY={y} />
```
> [!NOTE] Note that the page will not be scrolled to the initial value to avoid accessibility issues. Only subsequent changes to the bound variable of `scrollX` and `scrollY` will cause scrolling. If you have a legitimate reason to scroll when the component is rendered, call `scrollTo()` in an `$effect`.

@ -0,0 +1,28 @@
---
title: <svelte:document>
---
```svelte
<svelte:document onevent={handler} />
```
```svelte
<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](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.
```svelte
<svelte:document onvisibilitychange={handleVisibilityChange} use:someAction />
```
You can also bind to the following properties:
- `activeElement`
- `fullscreenElement`
- `pointerLockElement`
- `visibilityState`
All are readonly.

@ -0,0 +1,15 @@
---
title: <svelte:body>
---
```svelte
<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](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.
```svelte
<svelte:body onmouseenter={handleMouseenter} onmouseleave={handleMouseleave} use:someAction />
```

@ -0,0 +1,18 @@
---
title: <svelte:head>
---
```svelte
<svelte:head>...</svelte:head>
```
This element makes it possible to insert elements into `document.head`. During server-side rendering, `head` content is exposed separately to the main `body` content.
As with `<svelte:window>`, `<svelte:document>` and `<svelte:body>`, this element may only appear at the top level of your component and must never be inside a block or element.
```svelte
<svelte:head>
<title>Hello world!</title>
<meta name="description" content="This is where the description goes for SEO" />
</svelte:head>
```

@ -0,0 +1,31 @@
---
title: <svelte:element>
---
```svelte
<svelte:element this={expression} />
```
The `<svelte:element>` element lets you render an element that is unknown at author time, for example because it comes from a CMS. Any properties and event listeners present will be applied to the element.
The only supported binding is `bind:this`, since Svelte's built-in bindings do not work with generic elements.
If `this` has a nullish value, the element and its children will not be rendered.
If `this` is the name of a [void element](https://developer.mozilla.org/en-US/docs/Glossary/Void_element) (e.g., `br`) and `<svelte:element>` has child elements, a runtime error will be thrown in development mode:
```svelte
<script>
let tag = $state('hr');
</script>
<svelte:element this={tag}>
This text cannot appear inside an hr element
</svelte:element>
```
Svelte tries its best to infer the correct namespace from the element's surroundings, but it's not always possible. You can make it explicit with an `xmlns` attribute:
```svelte
<svelte:element this={tag} xmlns="http://www.w3.org/2000/svg" />
```

@ -0,0 +1,22 @@
---
title: <svelte:options>
---
```svelte
<svelte:options option={value} />
```
The `<svelte:options>` element provides a place to specify per-component compiler options, which are detailed in the [compiler section](svelte-compiler#compile). The possible options are:
- `immutable={true}` — you never use mutable data, so the compiler can do simple referential equality checks to determine if values have changed
- `immutable={false}` — the default. Svelte will be more conservative about whether or not mutable objects have changed
- `accessors={true}` — adds getters and setters for the component's props
- `accessors={false}` — the default
- `runes={true}` — forces a component into _runes mode_ (see the [Legacy APIs](legacy-overview) section)
- `runes={false}` — forces a component into _legacy mode_
- `namespace="..."` — the namespace where this component will be used, most commonly "svg"; use the "foreign" namespace to opt out of case-insensitive attribute names and HTML-specific warnings
- `customElement={...}` — the [options](custom-elements#Component-options) to use when compiling this component as a custom element. If a string is passed, it is used as the `tag` option
```svelte
<svelte:options customElement="my-custom-element" />
```

@ -1,190 +0,0 @@
---
title: Special elements
---
- [basically what we have in the docs today](https://svelte.dev/docs/special-elements)
Some of Svelte's concepts need special elements. Those are prefixed with `svelte:` and listed here.
## `<svelte:self>`
The `<svelte:self>` element allows a component to include itself, recursively.
It cannot appear at the top level of your markup; it must be inside an if or each block or passed to a component's slot to prevent an infinite loop.
```svelte
<script>
let { count } = $props();
</script>
{#if count > 0}
<p>counting down... {count}</p>
<svelte:self count={count - 1} />
{:else}
<p>lift-off!</p>
{/if}
```
## `<svelte:component>`
```svelte
<svelte:component this={expression} />
```
The `<svelte:component>` element renders a component dynamically, using the component constructor specified as the `this` property. When the property changes, the component is destroyed and recreated.
If `this` is falsy, no component is rendered.
```svelte
<svelte:component this={currentSelection.component} foo={bar} />
```
## `<svelte:element>`
```svelte
<svelte:element this={expression} />
```
The `<svelte:element>` element lets you render an element of a dynamically specified type. This is useful for example when displaying rich text content from a CMS. Any properties and event listeners present will be applied to the element.
The only supported binding is `bind:this`, since the element type-specific bindings that Svelte does at build time (e.g. `bind:value` for input elements) do not work with a dynamic tag type.
If `this` has a nullish value, the element and its children will not be rendered.
If `this` is the name of a [void element](https://developer.mozilla.org/en-US/docs/Glossary/Void_element) (e.g., `br`) and `<svelte:element>` has child elements, a runtime error will be thrown in development mode.
```svelte
<script>
let { handler } = $props();
let tag = $state('div');
</script>
<svelte:element this={tag} onclick={handler}>Foo</svelte:element>
```
Svelte tries its best to infer the correct namespace from the element's surroundings, but it's not always possible. You can make it explicit with an `xmlns` attribute:
```svelte
<svelte:element this={tag} xmlns="http://www.w3.org/2000/svg" />
```
## `<svelte:window>`
```svelte
<svelte:window onevent={handler} />
```
```svelte
<svelte:window bind:prop={value} />
```
The `<svelte:window>` element allows you to add event listeners to the `window` object without worrying about removing them when the component is destroyed, or checking for the existence of `window` when server-side rendering.
Unlike `<svelte:self>`, this element may only appear at the top level of your component and must never be inside a block or element.
```svelte
<script>
function handleKeydown(event) {
alert(`pressed the ${event.key} key`);
}
</script>
<svelte:window onkeydown={handleKeydown} />
```
You can also bind to the following properties:
- `innerWidth`
- `innerHeight`
- `outerWidth`
- `outerHeight`
- `scrollX`
- `scrollY`
- `online` — an alias for `window.navigator.onLine`
- `devicePixelRatio`
All except `scrollX` and `scrollY` are readonly.
```svelte
<svelte:window bind:scrollY={y} />
```
> [!NOTE] Note that the page will not be scrolled to the initial value to avoid accessibility issues. Only subsequent changes to the bound variable of `scrollX` and `scrollY` will cause scrolling. However, if the scrolling behaviour is desired, call `scrollTo()` in `onMount()`.
## `<svelte:document>`
```svelte
<svelte:document onevent={handler} />
```
```svelte
<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](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.
```svelte
<svelte:document onvisibilitychange={handleVisibilityChange} use:someAction />
```
You can also bind to the following properties:
- `activeElement`
- `fullscreenElement`
- `pointerLockElement`
- `visibilityState`
All are readonly.
## `<svelte:body>`
```svelte
<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](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.
```svelte
<svelte:body onmouseenter={handleMouseenter} onmouseleave={handleMouseleave} use:someAction />
```
## `<svelte:head>`
```svelte
<svelte:head>...</svelte:head>
```
This element makes it possible to insert elements into `document.head`. During server-side rendering, `head` content is exposed separately to the main `html` content.
As with `<svelte:window>`, `<svelte:document>` and `<svelte:body>`, this element may only appear at the top level of your component and must never be inside a block or element.
```svelte
<svelte:head>
<title>Hello world!</title>
<meta name="description" content="This is where the description goes for SEO" />
</svelte:head>
```
## `<svelte:options>`
```svelte
<svelte:options option={value} />
```
The `<svelte:options>` element provides a place to specify per-component compiler options, which are detailed in the [compiler section](svelte-compiler#compile). The possible options are:
- `immutable={true}` — you never use mutable data, so the compiler can do simple referential equality checks to determine if values have changed
- `immutable={false}` — the default. Svelte will be more conservative about whether or not mutable objects have changed
- `accessors={true}` — adds getters and setters for the component's props
- `accessors={false}` — the default
- `namespace="..."` — the namespace where this component will be used, most commonly "svg"; use the "foreign" namespace to opt out of case-insensitive attribute names and HTML-specific warnings
- `customElement={...}` — the [options](custom-elements#Component-options) to use when compiling this component as a custom element. If a string is passed, it is used as the `tag` option
```svelte
<svelte:options customElement="my-custom-element" />
```

@ -2,9 +2,9 @@
title: Stores
---
- how to use
<!-- - how to use
- how to write
- TODO should the details for the store methods belong to the reference section?
- TODO should the details for the store methods belong to the reference section? -->
A _store_ is an object that allows reactive access to a value via a simple _store contract_. The [`svelte/store` module](../svelte-store) contains minimal store implementations which fulfil this contract.

@ -2,8 +2,8 @@
title: Context
---
- get/set/hasContext
- how to use, best practises (like encapsulating them)
<!-- - get/set/hasContext
- how to use, best practises (like encapsulating them) -->
Most state is component-level state that lives as long as its component lives. There's also section-wide or app-wide state however, which also needs to be handled somehow.

@ -2,10 +2,10 @@
title: Lifecycle hooks
---
- onMount/onDestroy
<!-- - onMount/onDestroy
- mention that `$effect` might be better for your use case
- beforeUpdate/afterUpdate with deprecation notice?
- or skip this entirely and only have it in the reference docs?
- or skip this entirely and only have it in the reference docs? -->
In Svelte 5, the component lifecycle consists of only two parts: Its creation and its destruction. Everything in-between - when certain state is updated - is not related to the component as a whole, only the parts that need to react to the state change are notified. This is because under the hood the smallest unit of change is actually not a component, it's the (render) effects that the component sets up upon component initialization. Consequently, there's no such thing as a "before update"/"after update" hook.

@ -2,13 +2,13 @@
title: Imperative component API
---
better title needed?
<!-- better title needed?
- mount
- unmount
- render
- hydrate
- how they interact with each other
- how they interact with each other -->
Every Svelte application starts by imperatively creating a root component. On the client this component is mounted to a specific element. On the server, you want to get back a string of HTML instead which you can render. The following functions help you achieve those tasks.

@ -2,11 +2,11 @@
title: TypeScript
---
- [basically what we have today](https://svelte.dev/docs/typescript)
<!-- - [basically what we have today](https://svelte.dev/docs/typescript)
- built-in support, but only for type-only features
- generics
- using `Component` and the other helper types
- using `svelte-check`
- using `svelte-check` -->
You can use TypeScript within Svelte components. IDE extensions like the [Svelte VS Code extension](https://marketplace.visualstudio.com/items?itemName=svelte.svelte-vscode) will help you catch errors right in your editor, and [`svelte-check`](https://www.npmjs.com/package/svelte-check) does the same on the command line, which you can integrate into your CI.

@ -2,9 +2,9 @@
title: Custom elements
---
- [basically what we have today](https://svelte.dev/docs/custom-elements-api)
<!-- - [basically what we have today](https://svelte.dev/docs/custom-elements-api) -->
Svelte components can also be compiled to custom elements (aka web components) using the `customElement: true` compiler option. You should specify a tag name for the component using the `<svelte:options>` [element](special-elements#svelte:options).
Svelte components can also be compiled to custom elements (aka web components) using the `customElement: true` compiler option. You should specify a tag name for the component using the `<svelte:options>` [element](svelte-options).
```svelte
<svelte:options customElement="my-element" />

@ -2,4 +2,245 @@
title: Svelte 4 migration guide
---
TODO copy over existing https://svelte.dev/docs/v4-migration-guide
This migration guide provides an overview of how to migrate from Svelte version 3 to 4. See the linked PRs for more details about each change. Use the migration script to migrate some of these automatically: `npx svelte-migrate@latest svelte-4`
If you're a library author, consider whether to only support Svelte 4 or if it's possible to support Svelte 3 too. Since most of the breaking changes don't affect many people, this may be easily possible. Also remember to update the version range in your `peerDependencies`.
## Minimum version requirements
- Upgrade to Node 16 or higher. Earlier versions are no longer supported. ([#8566](https://github.com/sveltejs/svelte/issues/8566))
- If you are using SvelteKit, upgrade to 1.20.4 or newer ([sveltejs/kit#10172](https://github.com/sveltejs/kit/pull/10172))
- If you are using Vite without SvelteKit, upgrade to `vite-plugin-svelte` 2.4.1 or newer ([#8516](https://github.com/sveltejs/svelte/issues/8516))
- If you are using webpack, upgrade to webpack 5 or higher and `svelte-loader` 3.1.8 or higher. Earlier versions are no longer supported. ([#8515](https://github.com/sveltejs/svelte/issues/8515), [198dbcf](https://github.com/sveltejs/svelte/commit/198dbcf))
- If you are using Rollup, upgrade to `rollup-plugin-svelte` 7.1.5 or higher ([198dbcf](https://github.com/sveltejs/svelte/commit/198dbcf))
- If you are using TypeScript, upgrade to TypeScript 5 or higher. Lower versions might still work, but no guarantees are made about that. ([#8488](https://github.com/sveltejs/svelte/issues/8488))
## Browser conditions for bundlers
Bundlers must now specify the `browser` condition when building a frontend bundle for the browser. SvelteKit and Vite will handle this automatically for you. If you're using any others, you may observe lifecycle callbacks such as `onMount` not get called and you'll need to update the module resolution configuration.
- For Rollup this is done within the `@rollup/plugin-node-resolve` plugin by setting `browser: true` in its options. See the [`rollup-plugin-svelte`](https://github.com/sveltejs/rollup-plugin-svelte/#usage) documentation for more details
- For webpack this is done by adding `"browser"` to the `conditionNames` array. You may also have to update your `alias` config, if you have set it. See the [`svelte-loader`](https://github.com/sveltejs/svelte-loader#usage) documentation for more details
([#8516](https://github.com/sveltejs/svelte/issues/8516))
## Removal of CJS related output
Svelte no longer supports the CommonJS (CJS) format for compiler output and has also removed the `svelte/register` hook and the CJS runtime version. If you need to stay on the CJS output format, consider using a bundler to convert Svelte's ESM output to CJS in a post-build step. ([#8613](https://github.com/sveltejs/svelte/issues/8613))
## Stricter types for Svelte functions
There are now stricter types for `createEventDispatcher`, `Action`, `ActionReturn`, and `onMount`:
- `createEventDispatcher` now supports specifying that a payload is optional, required, or non-existent, and the call sites are checked accordingly ([#7224](https://github.com/sveltejs/svelte/issues/7224))
```ts
// @errors: 2554 2345
import { createEventDispatcher } from 'svelte';
const dispatch = createEventDispatcher<{
optional: number | null;
required: string;
noArgument: null;
}>();
// Svelte version 3:
dispatch('optional');
dispatch('required'); // I can still omit the detail argument
dispatch('noArgument', 'surprise'); // I can still add a detail argument
// Svelte version 4 using TypeScript strict mode:
dispatch('optional');
dispatch('required'); // error, missing argument
dispatch('noArgument', 'surprise'); // error, cannot pass an argument
```
- `Action` and `ActionReturn` have a default parameter type of `undefined` now, which means you need to type the generic if you want to specify that this action receives a parameter. The migration script will migrate this automatically ([#7442](https://github.com/sveltejs/svelte/pull/7442))
```ts
// @noErrors
---const action: Action = (node, params) => { ... } // this is now an error if you use params in any way---
+++const action: Action<HTMLElement, string> = (node, params) => { ... } // params is of type string+++
```
- `onMount` now shows a type error if you return a function asynchronously from it, because this is likely a bug in your code where you expect the callback to be called on destroy, which it will only do for synchronously returned functions ([#8136](https://github.com/sveltejs/svelte/issues/8136))
```js
// @noErrors
// Example where this change reveals an actual bug
onMount(
--- // someCleanup() not called because function handed to onMount is async
async () => {
const something = await foo();---
+++ // someCleanup() is called because function handed to onMount is sync
() => {
foo().then(something => {...});
// ...
return () => someCleanup();
}
);
```
## Custom Elements with Svelte
The creation of custom elements with Svelte has been overhauled and significantly improved. The `tag` option is deprecated in favor of the new `customElement` option:
```svelte
---<svelte:options tag="my-component" />---
+++<svelte:options customElement="my-component" />+++
```
This change was made to allow [more configurability](custom-elements#Component-options) for advanced use cases. The migration script will adjust your code automatically. The update timing of properties has changed slightly as well. ([#8457](https://github.com/sveltejs/svelte/issues/8457))
## SvelteComponentTyped is deprecated
`SvelteComponentTyped` is deprecated, as `SvelteComponent` now has all its typing capabilities. Replace all instances of `SvelteComponentTyped` with `SvelteComponent`.
```js
---import { SvelteComponentTyped } from 'svelte';---
+++import { SvelteComponent } from 'svelte';+++
---export class Foo extends SvelteComponentTyped<{ aProp: string }> {}---
+++export class Foo extends SvelteComponent<{ aProp: string }> {}+++
```
If you have used `SvelteComponent` as the component instance type previously, you may see a somewhat opaque type error now, which is solved by changing `: typeof SvelteComponent` to `: typeof SvelteComponent<any>`.
```svelte
<script>
import ComponentA from './ComponentA.svelte';
import ComponentB from './ComponentB.svelte';
import { SvelteComponent } from 'svelte';
let component: typeof SvelteComponent+++<any>+++;
function choseRandomly() {
component = Math.random() > 0.5 ? ComponentA : ComponentB;
}
</script>
<button on:click={choseRandomly}>random</button>
<svelte:element this={component} />
```
The migration script will do both automatically for you. ([#8512](https://github.com/sveltejs/svelte/issues/8512))
## Transitions are local by default
Transitions are now local by default to prevent confusion around page navigations. "local" means that a transition will not play if it's within a nested control flow block (`each/if/await/key`) and not the direct parent block but a block above it is created/destroyed. In the following example, the `slide` intro animation will only play when `success` goes from `false` to `true`, but it will _not_ play when `show` goes from `false` to `true`:
```svelte
{#if show}
...
{#if success}
<p in:slide>Success</p>
{/each}
{/if}
```
To make transitions global, add the `|global` modifier - then they will play when _any_ control flow block above is created/destroyed. The migration script will do this automatically for you. ([#6686](https://github.com/sveltejs/svelte/issues/6686))
## Default slot bindings
Default slot bindings are no longer exposed to named slots and vice versa:
```svelte
<script>
import Nested from './Nested.svelte';
</script>
<Nested let:count>
<p>
count in default slot - is available: {count}
</p>
<p slot="bar">
count in bar slot - is not available: {count}
</p>
</Nested>
```
This makes slot bindings more consistent as the behavior is undefined when for example the default slot is from a list and the named slot is not. ([#6049](https://github.com/sveltejs/svelte/issues/6049))
## Preprocessors
The order in which preprocessors are applied has changed. Now, preprocessors are executed in order, and within one group, the order is markup, script, style.
```js
// @errors: 2304
import { preprocess } from 'svelte/compiler';
const { code } = await preprocess(
source,
[
{
markup: () => {
console.log('markup-1');
},
script: () => {
console.log('script-1');
},
style: () => {
console.log('style-1');
}
},
{
markup: () => {
console.log('markup-2');
},
script: () => {
console.log('script-2');
},
style: () => {
console.log('style-2');
}
}
],
{
filename: 'App.svelte'
}
);
// Svelte 3 logs:
// markup-1
// markup-2
// script-1
// script-2
// style-1
// style-2
// Svelte 4 logs:
// markup-1
// script-1
// style-1
// markup-2
// script-2
// style-2
```
This could affect you for example if you are using `MDsveX` - in which case you should make sure it comes before any script or style preprocessor.
```js
// @noErrors
preprocess: [
--- vitePreprocess(),
mdsvex(mdsvexConfig)---
+++ mdsvex(mdsvexConfig),
vitePreprocess()+++
]
```
Each preprocessor must also have a name. ([#8618](https://github.com/sveltejs/svelte/issues/8618))
## New eslint package
`eslint-plugin-svelte3` is deprecated. It may still work with Svelte 4 but we make no guarantees about that. We recommend switching to our new package [eslint-plugin-svelte](https://github.com/sveltejs/eslint-plugin-svelte). See [this Github post](https://github.com/sveltejs/kit/issues/10242#issuecomment-1610798405) for an instruction how to migrate. Alternatively, you can create a new project using `npm create svelte@latest`, select the eslint (and possibly TypeScript) option and then copy over the related files into your existing project.
## Other breaking changes
- the `inert` attribute is now applied to outroing elements to make them invisible to assistive technology and prevent interaction. ([#8628](https://github.com/sveltejs/svelte/pull/8628))
- the runtime now uses `classList.toggle(name, boolean)` which may not work in very old browsers. Consider using a [polyfill](https://github.com/eligrey/classList.js) if you need to support these browsers. ([#8629](https://github.com/sveltejs/svelte/issues/8629))
- the runtime now uses the `CustomEvent` constructor which may not work in very old browsers. Consider using a [polyfill](https://github.com/theftprevention/event-constructor-polyfill/tree/master) if you need to support these browsers. ([#8775](https://github.com/sveltejs/svelte/pull/8775))
- people implementing their own stores from scratch using the `StartStopNotifier` interface (which is passed to the create function of `writable` etc) from `svelte/store` now need to pass an update function in addition to the set function. This has no effect on people using stores or creating stores using the existing Svelte stores. ([#6750](https://github.com/sveltejs/svelte/issues/6750))
- `derived` will now throw an error on falsy values instead of stores passed to it. ([#7947](https://github.com/sveltejs/svelte/issues/7947))
- type definitions for `svelte/internal` were removed to further discourage usage of those internal methods which are not public API. Most of these will likely change for Svelte 5
- Removal of DOM nodes is now batched which slightly changes its order, which might affect the order of events fired if you're using a `MutationObserver` on these elements ([#8763](https://github.com/sveltejs/svelte/pull/8763))
- if you enhanced the global typings through the `svelte.JSX` namespace before, you need to migrate this to use the `svelteHTML` namespace. Similarly if you used the `svelte.JSX` namespace to use type definitions from it, you need to migrate those to use the types from `svelte/elements` instead. You can find more information about what to do [here](https://github.com/sveltejs/language-tools/blob/master/docs/preprocessors/typescript.md#im-getting-deprecation-warnings-for-sveltejsx--i-want-to-migrate-to-the-new-typings)

@ -2,7 +2,7 @@
title: <svelte:fragment>
---
The `<svelte:fragment>` element allows you to place content in a [named slot](/docs/special-elements#slot-slot-name-name) without wrapping it in a container DOM element. This keeps the flow layout of your document intact.
The `<svelte:fragment>` element allows you to place content in a [named slot](legacy-slots) without wrapping it in a container DOM element. This keeps the flow layout of your document intact.
```svelte
<!--- file: Widget.svelte --->

Loading…
Cancel
Save