Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 44 additions & 49 deletions documentation/docs/07-misc/07-v5-migration-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -597,29 +597,58 @@ export declare const MyComponent: Component<{

To declare that a component of a certain type is required:

```svelte
<script lang="ts">
import type { ---SvelteComponent--- +++Component+++ } from 'svelte';
import {
ComponentA,
ComponentB
} from 'component-library';

---let component: typeof SvelteComponent<{ foo: string }>---
+++let component: Component<{ foo: string }>+++ = $state(
Math.random() ? ComponentA : ComponentB
);
</script>
```js
import { ComponentA, ComponentB } from 'component-library';
---import type { SvelteComponent } from 'svelte';---
+++import type { Component } from 'svelte';+++

<svelte:component this={component} foo="bar" />
---let C: typeof SvelteComponent<{ foo: string }> = $state(---
+++let C: Component<{ foo: string }> = $state(+++
Math.random() ? ComponentA : ComponentB
);
```

The two utility types `ComponentEvents` and `ComponentType` are also deprecated. `ComponentEvents` is obsolete because events are defined as callback props now, and `ComponentType` is obsolete because the new `Component` type is the component type already (e.g. `ComponentType<SvelteComponent<{ prop: string }>>` == `Component<{ prop: string }>`).
The two utility types `ComponentEvents` and `ComponentType` are also deprecated. `ComponentEvents` is obsolete because events are defined as callback props now, and `ComponentType` is obsolete because the new `Component` type is the component type already (i.e. `ComponentType<SvelteComponent<{ prop: string }>>` is equivalent to `Component<{ prop: string }>`).

### bind:this changes

Because components are no longer classes, using `bind:this` no longer returns a class instance with `$set`, `$on` and `$destroy` methods on it. It only returns the instance exports (`export function/const`) and, if you're using the `accessors` option, a getter/setter-pair for each property.

## `<svelte:component>` is no longer necessary

In Svelte 4, components are _static_ — if you render `<Thing>`, and the value of `Thing` changes, [nothing happens](/playground/7f1fa24f0ab44c1089dcbb03568f8dfa?version=4.2.18). To make it dynamic you had to use `<svelte:component>`.

This is no longer true in Svelte 5:

```svelte
<script>
import A from './A.svelte';
import B from './B.svelte';

let Thing = $state();
</script>

<select bind:value={Thing}>
<option value={A}>A</option>
<option value={B}>B</option>
</select>

<!-- these are equivalent -->
<Thing />
<svelte:component this={Thing} />
```
While migrating, keep in mind that your component's name should be capitalized (`Thing`) to distinguish it from elements, unless using dot notation.

### Dot notation indicates a component

In Svelte 4, `<foo.bar>` would create an element with a tag name of `"foo.bar"`. In Svelte 5, `foo.bar` is treated as a component instead. This is particularly useful inside `each` blocks:

```svelte
{#each items as item}
<item.component {...item.props} />
{/each}
```

## Whitespace handling changed

Previously, Svelte employed a very complicated algorithm to determine if whitespace should be kept or not. Svelte 5 simplifies this which makes it easier to reason about as a developer. The rules are:
Expand Down Expand Up @@ -653,16 +682,6 @@ The `legacy` compiler option, which generated bulkier but IE-friendly code, no l

Content inside component tags becomes a snippet prop called `children`. You cannot have a separate prop by that name.

## Dot notation indicates a component

In Svelte 4, `<foo.bar>` would create an element with a tag name of `"foo.bar"`. In Svelte 5, `foo.bar` is treated as a component instead. This is particularly useful inside `each` blocks:

```svelte
{#each items as item}
<item.component {...item.props} />
{/each}
```

## Breaking changes in runes mode

Some breaking changes only apply once your component is in runes mode.
Expand Down Expand Up @@ -700,30 +719,6 @@ In Svelte 4, doing the following triggered reactivity:

This is because the Svelte compiler treated the assignment to `foo.value` as an instruction to update anything that referenced `foo`. In Svelte 5, reactivity is determined at runtime rather than compile time, so you should define `value` as a reactive `$state` field on the `Foo` class. Wrapping `new Foo()` with `$state(...)` will have no effect — only vanilla objects and arrays are made deeply reactive.

### `<svelte:component>` is no longer necessary

In Svelte 4, components are _static_ — if you render `<Thing>`, and the value of `Thing` changes, [nothing happens](/playground/7f1fa24f0ab44c1089dcbb03568f8dfa?version=4.2.18). To make it dynamic you must use `<svelte:component>`.

This is no longer true in Svelte 5:

```svelte
<script>
import A from './A.svelte';
import B from './B.svelte';

let Thing = $state();
</script>

<select bind:value={Thing}>
<option value={A}>A</option>
<option value={B}>B</option>
</select>

<!-- these are equivalent -->
<Thing />
<svelte:component this={Thing} />
```

### Touch and wheel events are passive

When using `onwheel`, `onmousewheel`, `ontouchstart` and `ontouchmove` event attributes, the handlers are [passive](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#using_passive_listeners) to align with browser defaults. This greatly improves responsiveness by allowing the browser to scroll the document immediately, rather than waiting to see if the event handler calls `event.preventDefault()`.
Expand Down
2 changes: 1 addition & 1 deletion documentation/docs/99-legacy/30-legacy-svelte-component.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
title: <svelte:component>
---

In runes mode, `<MyComponent>` will re-render if the value of `MyComponent` changes. See the [Svelte 5 migration guide](/docs/svelte/v5-migration-guide#Breaking-changes-in-runes-mode-svelte:component-is-no-longer-necessary) for an example.
In runes mode, `<MyComponent>` will re-render if the value of `MyComponent` changes. See the [Svelte 5 migration guide](/docs/svelte/v5-migration-guide#svelte:component-is-no-longer-necessary) for an example.

In legacy mode, it won't — we must use `<svelte:component>`, which destroys and recreates the component instance when the value of its `this` expression changes:

Expand Down
Loading