docs: legacy docs

add docs on old syntax
pull/13756/head
Simon Holthausen 2 years ago
parent a6e416da8c
commit d68fd1694f

@ -50,6 +50,9 @@ A `<script>` tag with a `module` attribute runs once when the module first evalu
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. 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.
> [!LEGACY]
> In Svelte 4, this script tag was created using `<script context="module">`
## `<style>` ## `<style>`
CSS inside a `<style>` block will be scoped to that component. CSS inside a `<style>` block will be scoped to that component.

@ -5,3 +5,6 @@ title: .svelte.js and .svelte.ts files
Besides `.svelte` files, Svelte also operates on `.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. 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.
> [!LEGACY]
> This is a concept that didn't exist prior to Svelte 5

@ -19,3 +19,6 @@ They differ from normal JavaScript functions in important ways, however:
- You don't need to import them — they are part of the language - 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 - 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) - Just like JavaScript keywords, they are only valid in certain positions (the compiler will help you if you put them in the wrong place)
> [!LEGACY]
> Runes didn't exist prior to Svelte 5.

@ -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: $$props
---
`$$props` references all props that are passed to a component, including ones that are not declared with `export`. Using `$$props` will not perform as well as references to a specific prop because changes to any prop will cause Svelte to recheck all usages of `$$props`. But it can be useful in some cases for example, when you don't know at compile time what props might be passed to a component.
```svelte
<Widget {...$$props} />
```
> [!NOTE]
> In Svelte 5+, this concept is unnecessary as you can use [`let prop = $props()`]($props) 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,198 @@
---
title: Imperative component API
---
## Creating a component
```ts
// @noErrors
const component = new Component(options);
```
A client-side component — that is, a component compiled with `generate: 'dom'` (or the `generate` option left unspecified) is a JavaScript class.
```ts
// @noErrors
import App from './App.svelte';
const app = new App({
target: document.body,
props: {
// assuming App.svelte contains something like
// `export let answer`:
answer: 42
}
});
```
The following initialisation options can be provided:
| option | default | description |
| --------- | ----------- | ---------------------------------------------------------------------------------------------------- |
| `target` | **none** | An `HTMLElement` or `ShadowRoot` to render to. This option is required |
| `anchor` | `null` | A child of `target` to render the component immediately before |
| `props` | `{}` | An object of properties to supply to the component |
| `context` | `new Map()` | A `Map` of root-level context key-value pairs to supply to the component |
| `hydrate` | `false` | See below |
| `intro` | `false` | If `true`, will play transitions on initial render, rather than waiting for subsequent state changes |
Existing children of `target` are left where they are.
The `hydrate` option instructs Svelte to upgrade existing DOM (usually from server-side rendering) rather than creating new elements. It will only work if the component was compiled with the [`hydratable: true` option](/docs/svelte-compiler#compile). Hydration of `<head>` elements only works properly if the server-side rendering code was also compiled with `hydratable: true`, which adds a marker to each element in the `<head>` so that the component knows which elements it's responsible for removing during hydration.
Whereas children of `target` are normally left alone, `hydrate: true` will cause any children to be removed. For that reason, the `anchor` option cannot be used alongside `hydrate: true`.
The existing DOM doesn't need to match the component — Svelte will 'repair' the DOM as it goes.
```ts
/// file: index.js
// @noErrors
import App from './App.svelte';
const app = new App({
target: document.querySelector('#server-rendered-html'),
hydrate: true
});
```
> [!NOTE]
> In Svelte 5+, use [`mount`](svelte#mount) instead
## `$set`
```ts
// @noErrors
component.$set(props);
```
Programmatically sets props on an instance. `component.$set({ x: 1 })` is equivalent to `x = 1` inside the component's `<script>` block.
Calling this method schedules an update for the next microtask — the DOM is _not_ updated synchronously.
```ts
// @noErrors
component.$set({ answer: 42 });
```
> [!NOTE]
> In Svelte 5+, use `$state` instead to create a component props and update that
>
> ```js
> // @noErrors
> let props = $state({ answer: 42 });
> const component = mount(Component);
> // ...
> props.answer = 24;
> ```
## `$on`
```ts
// @noErrors
component.$on(ev, callback);
```
Causes the `callback` function to be called whenever the component dispatches an `event`.
A function is returned that will remove the event listener when called.
```ts
// @noErrors
const off = component.$on('selected', (event) => {
console.log(event.detail.selection);
});
off();
```
> [!NOTE]
> In Svelte 5+, pass callback props instead
## `$destroy`
```js
// @noErrors
component.$destroy();
```
Removes a component from the DOM and triggers any `onDestroy` handlers.
> [!NOTE]
> In Svelte 5+, use [`unmount`](svelte#unmount) instead
## Component props
```js
// @noErrors
component.prop;
```
```js
// @noErrors
component.prop = value;
```
If a component is compiled with `accessors: true`, each instance will have getters and setters corresponding to each of the component's props. Setting a value will cause a _synchronous_ update, rather than the default async update caused by `component.$set(...)`.
By default, `accessors` is `false`, unless you're compiling as a custom element.
```js
// @noErrors
console.log(component.count);
component.count += 1;
```
> [!NOTE]
> In Svelte 5+, this concept is obsolete. If you want to make properties accessible from the outside, `export` them
## Server-side component API
```js
// @noErrors
const result = Component.render(...)
```
Unlike client-side components, server-side components don't have a lifespan after you render them — their whole job is to create some HTML and CSS. For that reason, the API is somewhat different.
A server-side component exposes a `render` method that can be called with optional props. It returns an object with `head`, `html`, and `css` properties, where `head` contains the contents of any `<svelte:head>` elements encountered.
You can import a Svelte component directly into Node using [`svelte/register`](/docs/svelte-register).
```js
// @noErrors
require('svelte/register');
const App = require('./App.svelte').default;
const { head, html, css } = App.render({
answer: 42
});
```
The `.render()` method accepts the following parameters:
| parameter | default | description |
| --------- | ------- | -------------------------------------------------- |
| `props` | `{}` | An object of properties to supply to the component |
| `options` | `{}` | An object of options |
The `options` object takes in the following options:
| option | default | description |
| --------- | ----------- | ------------------------------------------------------------------------ |
| `context` | `new Map()` | A `Map` of root-level context key-value pairs to supply to the component |
```js
// @noErrors
const { head, html, css } = App.render(
// props
{ answer: 42 },
// options
{
context: new Map([['context-key', 'context-value']])
}
);
```
> [!NOTE]
> In Svelte 5+, use [`render`](svelte-server#render) instead

@ -0,0 +1,3 @@
---
title: Legacy syntax
---
Loading…
Cancel
Save