diff --git a/apps/svelte.dev/content/docs/svelte/01-introduction/03-svelte-files.md b/apps/svelte.dev/content/docs/svelte/01-introduction/03-svelte-files.md index f534e30fcb..e3dd72c222 100644 --- a/apps/svelte.dev/content/docs/svelte/01-introduction/03-svelte-files.md +++ b/apps/svelte.dev/content/docs/svelte/01-introduction/03-svelte-files.md @@ -50,6 +50,9 @@ A ` + + +``` + +Because Svelte's legacy mode reactivity is based on _assignments_, using array methods like `.push()` and `.splice()` won't automatically trigger updates. A subsequent assignment is required to 'tell' the compiler to update the UI: + +```svelte + +``` diff --git a/apps/svelte.dev/content/docs/svelte/99-legacy/02-legacy-reactive-assignments.md b/apps/svelte.dev/content/docs/svelte/99-legacy/02-legacy-reactive-assignments.md new file mode 100644 index 0000000000..5f7c9da790 --- /dev/null +++ b/apps/svelte.dev/content/docs/svelte/99-legacy/02-legacy-reactive-assignments.md @@ -0,0 +1,87 @@ +--- +title: Reactive $: statements +--- + +In runes mode, reactions to state updates are handled with the [`$derived`]($derived) and [`$effect`]($effect) runes. + +In legacy mode, any top-level statement (i.e. not inside a block or a function) can be made reactive by prefixing it with a `$:` [label](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/label). These statements run after other code in the ` +``` + +Statements are ordered _topologically_ by their dependencies and their assignments: since the `console.log` statement depends on `sum`, `sum` is calculated first even though it appears later in the source. + +Multiple statements can be combined by putting them in a block: + +```js +// @noErrors +$: { + // recalculate `total` when `items` changes + total = 0; + + for (const item of items) { + total += item.value; + } +} +``` + +The left-hand side of a reactive assignments can be an identifier, or it can be a destructuring assignment: + +```js +// @noErrors +$: ({ larry, moe, curly } = stooges); +``` + +## Understanding dependencies + +The dependencies of a `$:` statement are determined at compile time — they are whichever variables are referenced (but not assigned to) inside the statement. + +In other words, a statement like this will _not_ re-run when `count` changes, because the compiler cannot 'see' the dependency: + +```js +// @noErrors +let count = 0; +let double = () => count * 2; + +$: doubled = double(); +``` + +Similarly, topological ordering will fail if dependencies are referenced indirectly: `z` will never update, because `y` is not considered 'dirty' when the update occurs. Moving `$: z = y` below `$: setY(x)` will fix it: + +```svelte + +``` + +## Browser-only code + +Reactive statements run during server-side rendering as well as in the browser. This means that any code that should only run in the browser must be wrapped in an `if` block: + +```js +// @noErrors +$: if (browser) { + document.title = title; +} +``` diff --git a/apps/svelte.dev/content/docs/svelte/99-legacy/03-legacy-export-let.md b/apps/svelte.dev/content/docs/svelte/99-legacy/03-legacy-export-let.md new file mode 100644 index 0000000000..877e105b1f --- /dev/null +++ b/apps/svelte.dev/content/docs/svelte/99-legacy/03-legacy-export-let.md @@ -0,0 +1,72 @@ +--- +title: export let +--- + +In runes mode, [component props](basic-markup#Component-props) are declared with the [`$props`]($props) rune, allowing parent components to pass in data. + +In legacy mode, props are marked with the `export` keyword, and can have a default value: + +```svelte + +``` + +The default value is used if it would otherwise be `undefined` when the component is created. + +> [!NOTE] Unlike in runes mode, if the parent component changes a prop from a defined value to `undefined`, it does not revert to the initial value. + +Props without default values are considered _required_, and Svelte will print a warning during development if no value is provided, which you can squelch by specifying `undefined` as the default value: + +```js +export let foo +++= undefined;+++ +``` + +## Component exports + +An exported `const`, `class` or `function` declaration is _not_ considered a prop — instead, it becomes part of the component's API: + +```svelte + + +``` + +```svelte + + + + + + +``` + +## Renaming props + +The `export` keyword can appear separately from the declaration. This is useful for renaming props, for example in the case of a reserved word: + +```svelte + + +``` diff --git a/apps/svelte.dev/content/docs/svelte/99-legacy/04-legacy-$$props-and-$$restProps.md b/apps/svelte.dev/content/docs/svelte/99-legacy/04-legacy-$$props-and-$$restProps.md new file mode 100644 index 0000000000..33cac97035 --- /dev/null +++ b/apps/svelte.dev/content/docs/svelte/99-legacy/04-legacy-$$props-and-$$restProps.md @@ -0,0 +1,30 @@ +--- +title: $$props and $$restProps +--- + +In runes mode, getting an object containing all the props that were passed in is easy, using the [`$props`]($props) rune. + +In legacy mode, we use `$$props` and `$$restProps`: + +- `$$props` contains all the props that were passed in, including ones that are not individually declared with the `export` keyword +- `$$restProps` contains all the props that were passed in _except_ the ones that were individually declared + +For example, a ` + + +``` + +In Svelte 3/4 using `$$props` and `$$restProps` creates a modest performance penalty, so they should only be used when needed. diff --git a/apps/svelte.dev/content/docs/svelte/99-legacy/10-legacy-on.md b/apps/svelte.dev/content/docs/svelte/99-legacy/10-legacy-on.md new file mode 100644 index 0000000000..f2ee694cc1 --- /dev/null +++ b/apps/svelte.dev/content/docs/svelte/99-legacy/10-legacy-on.md @@ -0,0 +1,136 @@ +--- +title: on: +--- + +In runes mode, event handlers are just like any other attribute or prop. + +In legacy mode, we use the `on:` directive: + +```svelte + + + + +``` + +Handlers can be declared inline with no performance penalty: + +```svelte + +``` + +Add _modifiers_ to element event handlers with the `|` character. + +```svelte +
+ +
+``` + +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 + +``` + +It's possible to have multiple event listeners for the same event: + +```svelte + + + + +``` + +## Component events + +Components can dispatch events by creating a _dispatcher_ when they are initialised: + +```svelte + + + + + +``` + +`dispatch` creates a [`CustomEvent`](https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent). If a second argument is provided, it becomes the `detail` property of the event object. + +A consumer of this component can listen for the dispatched events: + +```svelte + + + n -= 1} + on:increment={() => n += 1} +/> + +

n: {n}

+``` + +Component events do not bubble — a parent component can only listen for events on its immediate children. + +Other than `once`, modifiers are not valid on component event handlers. + +> [!NOTE] +> If you're planning an eventual migration to Svelte 5, use callback props instead. This will make upgrading easier as `createEventDispatcher` is deprecated: +> +> ```svelte +> +> +> +> +> +> ``` diff --git a/apps/svelte.dev/content/docs/svelte/99-legacy/20-legacy-slots.md b/apps/svelte.dev/content/docs/svelte/99-legacy/20-legacy-slots.md new file mode 100644 index 0000000000..5189f2017d --- /dev/null +++ b/apps/svelte.dev/content/docs/svelte/99-legacy/20-legacy-slots.md @@ -0,0 +1,116 @@ +--- +title: +--- + +In Svelte 5, content can be passed to components in the form of [snippets](snippet) and rendered using [render tags](@render). + +In legacy mode, content inside component tags is considered _slotted content_, which can be rendered by the component using a `` element: + +```svelte + + + +This is some slotted content +``` + +```svelte + + +``` + +> [!NOTE] If you want to render a regular `` element, you can use ``. + +## Named slots + +A component can have _named_ slots in addition to the default slot. On the parent side, add a `slot="..."` attribute to an element, component or [``](legacy-svelte-fragment) directly inside the component tags. + +```svelte + + + +{#if open} + + This is some slotted content + + +++
+++ + + +++
+++ +
+{/if} +``` + +On the child side, add a corresponding `` element: + +```svelte + + +``` + +## Fallback content + +If no slotted content is provided, a component can define fallback content by putting it inside the `` element: + +```svelte + + This will be rendered if no slotted content is provided + +``` + +## Passing data to slotted content + +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 `` is equivalent to ``. + +```svelte + +
    + {#each items as item} +
  • + +
  • + {/each} +
+ + + +
{thing.text}
+
+``` + +Named slots can also expose values. The `let:` directive goes on the element with the `slot` attribute. + +```svelte + +
    + {#each items as item} +
  • + +
  • + {/each} +
+ + + + + +
{item.text}
+

Copyright (c) 2019 Svelte Industries

+
+``` + + diff --git a/apps/svelte.dev/content/docs/svelte/99-legacy/21-legacy-$$slots.md b/apps/svelte.dev/content/docs/svelte/99-legacy/21-legacy-$$slots.md new file mode 100644 index 0000000000..7ca1cef844 --- /dev/null +++ b/apps/svelte.dev/content/docs/svelte/99-legacy/21-legacy-$$slots.md @@ -0,0 +1,27 @@ +--- +title: $$slots +--- + +In runes mode, we know which [snippets](snippet) were provided to a component, as they're just normal props. + +In legacy mode, the way to know if content was provided for a given slot is with the `$$slots` object, whose keys are the names of the slots passed into the component by the parent. + +```svelte + +
+ + {#if $$slots.description} + +
+ + {/if} +
+``` + +```svelte + + +

Blog Post Title

+ +
+``` diff --git a/apps/svelte.dev/content/docs/svelte/99-legacy/22-legacy-svelte-fragment.md b/apps/svelte.dev/content/docs/svelte/99-legacy/22-legacy-svelte-fragment.md new file mode 100644 index 0000000000..8827ab53cb --- /dev/null +++ b/apps/svelte.dev/content/docs/svelte/99-legacy/22-legacy-svelte-fragment.md @@ -0,0 +1,32 @@ +--- +title: +--- + +The `` 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 + +
+ No header was provided +

Some content between header and footer

+ +
+``` + +```svelte + + + + +

Hello

+ +

All rights reserved.

+

Copyright (c) 2019 Svelte Industries

+
+
+``` + +> [!NOTE] +> In Svelte 5+, this concept is obsolete, as snippets don't create a wrapping element diff --git a/apps/svelte.dev/content/docs/svelte/99-legacy/30-legacy-svelte-component.md b/apps/svelte.dev/content/docs/svelte/99-legacy/30-legacy-svelte-component.md new file mode 100644 index 0000000000..5d385a9c02 --- /dev/null +++ b/apps/svelte.dev/content/docs/svelte/99-legacy/30-legacy-svelte-component.md @@ -0,0 +1,13 @@ +--- +title: +--- + +In runes mode, `` will re-render if the value of `MyComponent` changes. + +In legacy mode, it won't — we must use ``, which destroys and recreates the component instance when the value of its `this` expression changes: + +```svelte + +``` + +If `this` is falsy, no component is rendered. diff --git a/apps/svelte.dev/content/docs/svelte/99-legacy/31-legacy-svelte-self.md b/apps/svelte.dev/content/docs/svelte/99-legacy/31-legacy-svelte-self.md new file mode 100644 index 0000000000..bfd140ac49 --- /dev/null +++ b/apps/svelte.dev/content/docs/svelte/99-legacy/31-legacy-svelte-self.md @@ -0,0 +1,37 @@ +--- +title: +--- + +The `` 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 + + +{#if count > 0} +

counting down... {count}

+ +{:else} +

lift-off!

+{/if} +``` + +> [!NOTE] +> This concept is obsolete, as components can import themselves: +> ```svelte +> +> +> +> {#if count > 0} +>

counting down... {count}

+> +> {:else} +>

lift-off!

+> {/if} +> ``` diff --git a/apps/svelte.dev/content/docs/svelte/99-legacy/40-legacy-component-api.md b/apps/svelte.dev/content/docs/svelte/99-legacy/40-legacy-component-api.md new file mode 100644 index 0000000000..5bbe7e7237 --- /dev/null +++ b/apps/svelte.dev/content/docs/svelte/99-legacy/40-legacy-component-api.md @@ -0,0 +1,200 @@ +--- +title: Imperative component API +--- + +In Svelte 3 and 4, the API for interacting with a component is different than in Svelte 5. Note that this page does _not_ apply to legacy mode components in a Svelte 5 application. + +## 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 `` 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 `` 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 `