mirror of https://github.com/sveltejs/svelte
parent
a6e416da8c
commit
d68fd1694f
@ -0,0 +1,7 @@
|
||||
---
|
||||
title: Overview
|
||||
---
|
||||
|
||||
Svelte 5 came with some significant changes to Svelte's API. These include runes, snippets and event attributes. As a result some of the API known from Svelte 3 and 4 is deprecated and will be removed at some point in the future. It is advised to incrementally migrate towards the new syntax, see the [migration guide](v5-migration-guide) for more info.
|
||||
|
||||
That said, this legacy syntax is still available today and can be used side by side with the new syntax. The following pages contain reference documentation of said syntax.
|
||||
@ -0,0 +1,49 @@
|
||||
---
|
||||
title: let is reactive
|
||||
---
|
||||
|
||||
To change component state and trigger a re-render, just assign to a locally declared variable.
|
||||
|
||||
Update expressions (`count += 1`) and property assignments (`obj.x = y`) have the same effect.
|
||||
|
||||
```svelte
|
||||
<script>
|
||||
let count = 0;
|
||||
|
||||
function handleClick() {
|
||||
// calling this function will trigger an
|
||||
// update if the markup references `count`
|
||||
count = count + 1;
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
Because Svelte's reactivity is based on assignments, using array methods like `.push()` and `.splice()` won't automatically trigger updates. A subsequent assignment is required to trigger the update. This and more details can also be found in the [tutorial](https://learn.svelte.dev/tutorial/updating-arrays-and-objects).
|
||||
|
||||
```svelte
|
||||
<script>
|
||||
let arr = [0, 1];
|
||||
|
||||
function handleClick() {
|
||||
// this method call does not trigger an update
|
||||
arr.push(2);
|
||||
// this assignment will trigger an update
|
||||
// if the markup references `arr`
|
||||
arr = arr;
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
Svelte's `<script>` blocks are run only when the component is created, so assignments within a `<script>` block are not automatically run again when a prop updates. If you'd like to track changes to a prop, see the next example in the following section.
|
||||
|
||||
```svelte
|
||||
<script>
|
||||
export let person;
|
||||
// this will only set `name` on component creation
|
||||
// it will not update when `person` does
|
||||
let { name } = person;
|
||||
</script>
|
||||
```
|
||||
|
||||
> [!NOTE]
|
||||
> In Svelte 5+, state is explicitly reactive via the [`$state` rune]($state)
|
||||
@ -0,0 +1,87 @@
|
||||
---
|
||||
title: $:
|
||||
---
|
||||
|
||||
Any top-level statement (i.e. not inside a block or a function) can be made reactive by prefixing it with the `$:` [JS label syntax](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/label). Reactive statements run after other script code and before the component markup is rendered, whenever the values that they depend on have changed.
|
||||
|
||||
```svelte
|
||||
<script>
|
||||
export let title;
|
||||
export let person;
|
||||
|
||||
// this will update `document.title` whenever
|
||||
// the `title` prop changes
|
||||
$: document.title = title;
|
||||
|
||||
$: {
|
||||
console.log(`multiple statements can be combined`);
|
||||
console.log(`the current title is ${title}`);
|
||||
}
|
||||
|
||||
// this will update `name` when 'person' changes
|
||||
$: ({ name } = person);
|
||||
|
||||
// don't do this. it will run before the previous line
|
||||
let name2 = name;
|
||||
</script>
|
||||
```
|
||||
|
||||
Only values which directly appear within the `$:` block will become dependencies of the reactive statement. For example, in the code below `total` will only update when `x` changes, but not `y`.
|
||||
|
||||
```svelte
|
||||
<!--- file: App.svelte --->
|
||||
<script>
|
||||
let x = 0;
|
||||
let y = 0;
|
||||
|
||||
/** @param {number} value */
|
||||
function yPlusAValue(value) {
|
||||
return value + y;
|
||||
}
|
||||
|
||||
$: total = yPlusAValue(x);
|
||||
</script>
|
||||
|
||||
Total: {total}
|
||||
<button on:click={() => x++}> Increment X </button>
|
||||
|
||||
<button on:click={() => y++}> Increment Y </button>
|
||||
```
|
||||
|
||||
It is important to note that the reactive blocks are ordered via simple static analysis at compile time, and all the compiler looks at are the variables that are assigned to and used within the block itself, not in any functions called by them. This means that `yDependent` will not be updated when `x` is updated in the following example:
|
||||
|
||||
```svelte
|
||||
<!--- file: App.svelte --->
|
||||
<script>
|
||||
let x = 0;
|
||||
let y = 0;
|
||||
|
||||
/** @param {number} value */
|
||||
function setY(value) {
|
||||
y = value;
|
||||
}
|
||||
|
||||
$: yDependent = y;
|
||||
$: setY(x);
|
||||
</script>
|
||||
```
|
||||
|
||||
Moving the line `$: yDependent = y` below `$: setY(x)` will cause `yDependent` to be updated when `x` is updated.
|
||||
|
||||
If a statement consists entirely of an assignment to an undeclared variable, Svelte will inject a `let` declaration on your behalf.
|
||||
|
||||
```svelte
|
||||
<!--- file: App.svelte --->
|
||||
<script>
|
||||
/** @type {number} */
|
||||
export let num;
|
||||
|
||||
// we don't need to declare `squared` and `cubed`
|
||||
// — Svelte does it for us
|
||||
$: squared = num * num;
|
||||
$: cubed = squared * num;
|
||||
</script>
|
||||
```
|
||||
|
||||
> [!NOTE]
|
||||
> In Svelte 5+, reactions are handled via the [`$derived`]($derived) and [`$effect`]($effect) runes
|
||||
@ -0,0 +1,63 @@
|
||||
---
|
||||
title: export let
|
||||
---
|
||||
|
||||
Svelte uses the `export` keyword to mark a variable declaration as a _property_ or _prop_, which means it becomes accessible to consumers of the component (see the section on [attributes and props](/docs/basic-markup#attributes-and-props) for more information).
|
||||
|
||||
```svelte
|
||||
<script>
|
||||
export let foo;
|
||||
|
||||
// Values that are passed in as props
|
||||
// are immediately available
|
||||
console.log({ foo });
|
||||
</script>
|
||||
```
|
||||
|
||||
You can specify a default initial value for a prop. It will be used if the component's consumer doesn't specify the prop on the component (or if its initial value is `undefined`) when instantiating the component. Note that if the values of props are subsequently updated, then any prop whose value is not specified will be set to `undefined` (rather than its initial value).
|
||||
|
||||
In development mode (see the [compiler options](/docs/svelte-compiler#compile)), a warning will be printed if no default initial value is provided and the consumer does not specify a value. To squelch this warning, ensure that a default initial value is specified, even if it is `undefined`.
|
||||
|
||||
```svelte
|
||||
<script>
|
||||
export let bar = 'optional default initial value';
|
||||
export let baz = undefined;
|
||||
</script>
|
||||
```
|
||||
|
||||
If you export a `const`, `class` or `function`, it is readonly from outside the component. Functions are valid prop values, however, as shown below.
|
||||
|
||||
```svelte
|
||||
<!--- file: App.svelte --->
|
||||
<script>
|
||||
// these are readonly
|
||||
export const thisIs = 'readonly';
|
||||
|
||||
/** @param {string} name */
|
||||
export function greet(name) {
|
||||
alert(`hello ${name}!`);
|
||||
}
|
||||
|
||||
// this is a prop
|
||||
export let format = (n) => n.toFixed(2);
|
||||
</script>
|
||||
```
|
||||
|
||||
Readonly props can be accessed as properties on the element, tied to the component using [`bind:this` syntax](/docs/component-directives#bind-this).
|
||||
|
||||
You can use reserved words as prop names.
|
||||
|
||||
```svelte
|
||||
<!--- file: App.svelte --->
|
||||
<script>
|
||||
/** @type {string} */
|
||||
let className;
|
||||
|
||||
// creates a `class` property, even
|
||||
// though it is a reserved word
|
||||
export { className as class };
|
||||
</script>
|
||||
```
|
||||
|
||||
> [!NOTE]
|
||||
> In Svelte 5+, use the [`$props`]($props) rune instead
|
||||
@ -0,0 +1,12 @@
|
||||
---
|
||||
title: $$restProps
|
||||
---
|
||||
|
||||
`$$restProps` contains only the props which are _not_ declared with `export`. It can be used to pass down other unknown attributes to an element in a component. It shares the same performance characteristics compared to specific property access as `$$props`.
|
||||
|
||||
```svelte
|
||||
<input {...$$restProps} />
|
||||
```
|
||||
|
||||
> [!NOTE]
|
||||
> In Svelte 5+, this concept is unnecessary as you can use [`let { foo, ...rest } = $props()`]($props) instead
|
||||
@ -0,0 +1,129 @@
|
||||
---
|
||||
title: on:
|
||||
---
|
||||
|
||||
```svelte
|
||||
<!--- copy: false --->
|
||||
on:eventname={handler}
|
||||
```
|
||||
|
||||
```svelte
|
||||
<!--- copy: false --->
|
||||
on:eventname|modifiers={handler}
|
||||
```
|
||||
|
||||
Use the `on:` directive to listen to DOM events.
|
||||
|
||||
```svelte
|
||||
<!--- file: App.svelte --->
|
||||
<script>
|
||||
let count = 0;
|
||||
|
||||
/** @param {MouseEvent} event */
|
||||
function handleClick(event) {
|
||||
count += 1;
|
||||
}
|
||||
</script>
|
||||
|
||||
<button on:click={handleClick}>
|
||||
count: {count}
|
||||
</button>
|
||||
```
|
||||
|
||||
Handlers can be declared inline with no performance penalty. As with attributes, directive values may be quoted for the sake of syntax highlighters.
|
||||
|
||||
```svelte
|
||||
<button on:click={() => (count += 1)}>
|
||||
count: {count}
|
||||
</button>
|
||||
```
|
||||
|
||||
Add _modifiers_ to DOM events with the `|` character.
|
||||
|
||||
```svelte
|
||||
<form on:submit|preventDefault={handleSubmit}>
|
||||
<!-- the `submit` event's default is prevented,
|
||||
so the page won't reload -->
|
||||
</form>
|
||||
```
|
||||
|
||||
The following modifiers are available:
|
||||
|
||||
- `preventDefault` — calls `event.preventDefault()` before running the handler
|
||||
- `stopPropagation` — calls `event.stopPropagation()`, preventing the event reaching the next element
|
||||
- `stopImmediatePropagation` - calls `event.stopImmediatePropagation()`, preventing other listeners of the same event from being fired.
|
||||
- `passive` — improves scrolling performance on touch/wheel events (Svelte will add it automatically where it's safe to do so)
|
||||
- `nonpassive` — explicitly set `passive: false`
|
||||
- `capture` — fires the handler during the _capture_ phase instead of the _bubbling_ phase
|
||||
- `once` — remove the handler after the first time it runs
|
||||
- `self` — only trigger handler if `event.target` is the element itself
|
||||
- `trusted` — only trigger handler if `event.isTrusted` is `true`. I.e. if the event is triggered by a user action.
|
||||
|
||||
Modifiers can be chained together, e.g. `on:click|once|capture={...}`.
|
||||
|
||||
If the `on:` directive is used without a value, the component will _forward_ the event, meaning that a consumer of the component can listen for it.
|
||||
|
||||
```svelte
|
||||
<button on:click> The component itself will emit the click event </button>
|
||||
```
|
||||
|
||||
It's possible to have multiple event listeners for the same event:
|
||||
|
||||
```svelte
|
||||
<!--- file: App.svelte --->
|
||||
<script>
|
||||
let counter = 0;
|
||||
function increment() {
|
||||
counter = counter + 1;
|
||||
}
|
||||
|
||||
/** @param {MouseEvent} event */
|
||||
function track(event) {
|
||||
trackEvent(event);
|
||||
}
|
||||
</script>
|
||||
|
||||
<button on:click={increment} on:click={track}>Click me!</button>
|
||||
```
|
||||
|
||||
> [!NOTE]
|
||||
> In Svelte 5+, use event attributes instead
|
||||
> ```svelte
|
||||
> <button onclick={() => alert('clicked')}>click me</button>
|
||||
> ```
|
||||
|
||||
## Component events
|
||||
|
||||
Component events created with [`createEventDispatcher`](svelte#createEventDispatcher) create a `CustomEvent`. These events do not bubble. The detail argument corresponds to the `CustomEvent.detail` property and can contain any type of data.
|
||||
|
||||
```svelte
|
||||
<script>
|
||||
import { createEventDispatcher } from 'svelte';
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
</script>
|
||||
|
||||
<button on:click={() => dispatch('notify', 'detail value')}>Fire Event</button>
|
||||
```
|
||||
|
||||
Events dispatched from child components can be listened to in their parent. Any data provided when the event was dispatched is available on the `detail` property of the event object.
|
||||
|
||||
```svelte
|
||||
<script>
|
||||
function callbackFunction(event) {
|
||||
console.log(`Notify fired! Detail: ${event.detail}`);
|
||||
}
|
||||
</script>
|
||||
|
||||
<Child on:notify={callbackFunction} />
|
||||
```
|
||||
|
||||
> [!NOTE]
|
||||
> If you're planning on migrating to Svelte 5, use callback props instead. This will make upgrading easier as `createEventDispatcher` is deprecated
|
||||
> ```svelte
|
||||
> <script>
|
||||
> export let notify;
|
||||
> </script>
|
||||
>
|
||||
> <button on:click={() => notify('detail value')}>Fire Event</button>
|
||||
> ```
|
||||
@ -0,0 +1,124 @@
|
||||
---
|
||||
title: <slot>
|
||||
---
|
||||
|
||||
```svelte
|
||||
<slot><!-- optional fallback --></slot>
|
||||
```
|
||||
|
||||
```svelte
|
||||
<slot name="x"><!-- optional fallback --></slot>
|
||||
```
|
||||
|
||||
```svelte
|
||||
<slot prop={value} />
|
||||
```
|
||||
|
||||
Components can have child content, in the same way that elements can.
|
||||
|
||||
The content is exposed in the child component using the `<slot>` element, which can contain fallback content that is rendered if no children are provided.
|
||||
|
||||
```svelte
|
||||
<!-- Widget.svelte -->
|
||||
<div>
|
||||
<slot>
|
||||
this fallback content will be rendered when no content is provided, like in the first example
|
||||
</slot>
|
||||
</div>
|
||||
|
||||
<!-- App.svelte -->
|
||||
<Widget />
|
||||
<!-- this component will render the default content -->
|
||||
|
||||
<Widget>
|
||||
<p>this is some child content that will overwrite the default slot content</p>
|
||||
</Widget>
|
||||
```
|
||||
|
||||
Note: If you want to render regular `<slot>` element, You can use `<svelte:element this="slot" />`.
|
||||
|
||||
> [!NOTE]
|
||||
> In Svelte 5+, use snippets instead
|
||||
|
||||
## `<slot name="`_name_`">`
|
||||
|
||||
Named slots allow consumers to target specific areas. They can also have fallback content.
|
||||
|
||||
```svelte
|
||||
<!-- Widget.svelte -->
|
||||
<div>
|
||||
<slot name="header">No header was provided</slot>
|
||||
<p>Some content between header and footer</p>
|
||||
<slot name="footer" />
|
||||
</div>
|
||||
|
||||
<!-- App.svelte -->
|
||||
<Widget>
|
||||
<h1 slot="header">Hello</h1>
|
||||
<p slot="footer">Copyright (c) 2019 Svelte Industries</p>
|
||||
</Widget>
|
||||
```
|
||||
|
||||
Components can be placed in a named slot using the syntax `<Component slot="name" />`.
|
||||
In order to place content in a slot without using a wrapper element, you can use the special element `<svelte:fragment>`.
|
||||
|
||||
```svelte
|
||||
<!-- Widget.svelte -->
|
||||
<div>
|
||||
<slot name="header">No header was provided</slot>
|
||||
<p>Some content between header and footer</p>
|
||||
<slot name="footer" />
|
||||
</div>
|
||||
|
||||
<!-- App.svelte -->
|
||||
<Widget>
|
||||
<HeaderComponent slot="header" />
|
||||
<svelte:fragment slot="footer">
|
||||
<p>All rights reserved.</p>
|
||||
<p>Copyright (c) 2019 Svelte Industries</p>
|
||||
</svelte:fragment>
|
||||
</Widget>
|
||||
```
|
||||
|
||||
## `<slot key={`_value_`}>`
|
||||
|
||||
Slots can be rendered zero or more times and can pass values _back_ to the parent using props. The parent exposes the values to the slot template using the `let:` directive.
|
||||
|
||||
The usual shorthand rules apply — `let:item` is equivalent to `let:item={item}`, and `<slot {item}>` is equivalent to `<slot item={item}>`.
|
||||
|
||||
```svelte
|
||||
<!-- FancyList.svelte -->
|
||||
<ul>
|
||||
{#each items as item}
|
||||
<li class="fancy">
|
||||
<slot prop={item} />
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
||||
|
||||
<!-- App.svelte -->
|
||||
<FancyList {items} let:prop={thing}>
|
||||
<div>{thing.text}</div>
|
||||
</FancyList>
|
||||
```
|
||||
|
||||
Named slots can also expose values. The `let:` directive goes on the element with the `slot` attribute.
|
||||
|
||||
```svelte
|
||||
<!-- FancyList.svelte -->
|
||||
<ul>
|
||||
{#each items as item}
|
||||
<li class="fancy">
|
||||
<slot name="item" {item} />
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
||||
|
||||
<slot name="footer" />
|
||||
|
||||
<!-- App.svelte -->
|
||||
<FancyList {items}>
|
||||
<div slot="item" let:item>{item.text}</div>
|
||||
<p slot="footer">Copyright (c) 2019 Svelte Industries</p>
|
||||
</FancyList>
|
||||
```
|
||||
@ -0,0 +1,28 @@
|
||||
---
|
||||
title: $$slots
|
||||
---
|
||||
|
||||
`$$slots` is an object whose keys are the names of the slots passed into the component by the parent. If the parent does not pass in a slot with a particular name, that name will not be present in `$$slots`. This allows components to render a slot (and other elements, like wrappers for styling) only if the parent provides it.
|
||||
|
||||
Note that explicitly passing in an empty named slot will add that slot's name to `$$slots`. For example, if a parent passes `<div slot="title" />` to a child component, `$$slots.title` will be truthy within the child.
|
||||
|
||||
```svelte
|
||||
<!-- Card.svelte -->
|
||||
<div>
|
||||
<slot name="title" />
|
||||
{#if $$slots.description}
|
||||
<!-- This <hr> and slot will render only if a slot named "description" is provided. -->
|
||||
<hr />
|
||||
<slot name="description" />
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<!-- App.svelte -->
|
||||
<Card>
|
||||
<h1 slot="title">Blog Post Title</h1>
|
||||
<!-- No slot named "description" was provided so the optional slot will not be rendered. -->
|
||||
</Card>
|
||||
```
|
||||
|
||||
> [!NOTE]
|
||||
> In Svelte 5+, this concept is obsolete, as you pass snippets as component props and can check whether or not that prop is set
|
||||
@ -0,0 +1,26 @@
|
||||
---
|
||||
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.
|
||||
|
||||
```svelte
|
||||
<!-- Widget.svelte -->
|
||||
<div>
|
||||
<slot name="header">No header was provided</slot>
|
||||
<p>Some content between header and footer</p>
|
||||
<slot name="footer" />
|
||||
</div>
|
||||
|
||||
<!-- App.svelte -->
|
||||
<Widget>
|
||||
<h1 slot="header">Hello</h1>
|
||||
<svelte:fragment slot="footer">
|
||||
<p>All rights reserved.</p>
|
||||
<p>Copyright (c) 2019 Svelte Industries</p>
|
||||
</svelte:fragment>
|
||||
</Widget>
|
||||
```
|
||||
|
||||
> [!NOTE]
|
||||
> In Svelte 5+, this concept is obsolete, as snippets don't create a wrapping element
|
||||
@ -0,0 +1,27 @@
|
||||
---
|
||||
title: <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} />
|
||||
```
|
||||
|
||||
> [!NOTE]
|
||||
> In Svelte 5+, this concept is obsolete, as you can just reference `$state` or `$derived` variables containing components
|
||||
> ```svelte
|
||||
> <script>
|
||||
> let Component = $derived(currentSelection.component);
|
||||
> </script>
|
||||
>
|
||||
> <Component />
|
||||
> <!-- or -->
|
||||
> <currentSelection.component foo={bar} />
|
||||
> ```
|
||||
@ -0,0 +1,37 @@
|
||||
---
|
||||
title: <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>
|
||||
export let count;
|
||||
</script>
|
||||
|
||||
{#if count > 0}
|
||||
<p>counting down... {count}</p>
|
||||
<svelte:self count={count - 1} />
|
||||
{:else}
|
||||
<p>lift-off!</p>
|
||||
{/if}
|
||||
```
|
||||
|
||||
> [!NOTE]
|
||||
> This concept is obsolete, as you can just self-import components
|
||||
> ```svelte
|
||||
> <!--- file: App.svelte --->
|
||||
> <script>
|
||||
> import Self from './App.svelte'
|
||||
> export let count;
|
||||
> </script>
|
||||
>
|
||||
> {#if count > 0}
|
||||
> <p>counting down... {count}</p>
|
||||
> <Self count={count - 1} />
|
||||
> {:else}
|
||||
> <p>lift-off!</p>
|
||||
> {/if}
|
||||
> ```
|
||||
@ -0,0 +1,3 @@
|
||||
---
|
||||
title: Legacy syntax
|
||||
---
|
||||
Loading…
Reference in new issue