` 内のすべてをターゲットにします: ```svelte ``` # {@attach ...} Attachment は要素がDOMにマウントされたとき、または関数内で読み取られる [state]($state) が更新されたときに、 [effect]($effect) 内で実行される関数です。 オプションとして、 attachment が再実行される前、または要素がDOMから削除された後に呼び出される関数を返すこともできます。 > [!NOTE] > attachment は Svelte 5.29 以降で利用できます。 ```svelte ... ``` ひとつの要素はいくつでも attachment を持つことができます。 ## Attachmentファクトリ 便利なパターンとして、例にある `tooltip` のような関数が attachment を返す方法があります(デモ: ```svelte Hover me ``` `tooltip(content)` 式は [effect]($effect) 内で実行されるため、 `content` が変更されるたびに attachment は破棄され再作成されます。attachment 関数の _内部_ で読み取られた state についても、最初に実行されたときに同じことが起こります。 (これが望ましくないときは、 [Attachment の再実行タイミングを制御する](#Controlling-when-attachments-re-run) を参照してください。) ## インライン attachment Attachments はインラインで作成することもできます (デモ: ```svelte { const context = canvas.getContext('2d'); $effect(() => { context.fillStyle = color; context.fillRect(0, 0, canvas.width, canvas.height); }); }} > ``` > [!NOTE] > ネストされた effect は `color` が変更されるたびに実行されますが、外部の effect (`canvas.getContext(...)` が呼び出される箇所) はリアクティブな state を読み取らないため、一度しか実行されません。 ## Conditional attachments Falsy values like `false` or `undefined` are treated as no attachment, enabling conditional usage: ```svelte ... ``` ## コンポーネントへの attachment の受け渡し コンポーネントで `{@attach ...}` を使うと、キーが [`Symbol`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol) の props を作成します。コンポーネントが props を要素に [展開(spreads)](/tutorial/svelte/spread-props) すると、その要素は展開された attachment を受け取ります。 これにより、要素を拡張する _ラッパーコンポーネント_ を作成できます (デモ: ```svelte {@render children?.()} ``` ```svelte Hover me ``` ## Attachment の再実行タイミングを制御する attachment は [actions](use) と異なり、完全にリアクティブです。 `{@attach foo(bar)}` は `foo` _または_ `bar` (あるいは `foo` の内部で読み取られた state) の変更で再実行されます: ```js // @errors: 7006 2304 2552 function foo(bar) { return (node) => { veryExpensiveSetupWork(node); update(node, bar); }; } ``` まれにこれが問題になるとき(例えば `foo` が高コストかつ避けられないセットアップ作業をするときなど)には、データを関数内で渡し、子 effect で読み取ることを検討してください: ```js // @errors: 7006 2304 2552 function foo(+++getBar+++) { return (node) => { veryExpensiveSetupWork(node); +++ $effect(() => { update(node, getBar()); });+++ } } ``` ## プログラムによる attachment の作成 コンポーネントや要素に展開されるオブジェクトに attachment を追加するには、 [`createAttachmentKey`](svelte-attachments#createAttachmentKey) を使います。 ## action から attachment への変換 action のみを提供するライブラリを使用している場合、 [`fromAction`](svelte-attachments#fromAction) で action を attachment に変換できます。これにより、(例えば)コンポーネントで使えるようになります。 # {@const ...} `{@const ...}` タグはローカル定数を定義します。 ```svelte {#each boxes as box} {@const area = box.width * box.height} {box.width} * {box.height} = {area} {/each} ``` `{@const}` は、`{#if ...}`、`{#each ...}`、`{#snippet ...}` などのブロックや、``、または `` の直下の子としてのみ使用可能です。 # {@debug ...} `{@debug ...}` タグは、`console.log(...)` の代替手段を提供します。このタグは、特定の変数の値が変更されるたびにその値をログ出力し、開発者ツールが開いている場合はコードの実行を一時停止します。 ```svelte {@debug user} Hello {user.firstname}! ``` `{@debug ...}` は、変数名をカンマ区切りで指定することができます (任意の式は指定できません)。 ```svelte {@debug user} {@debug user1, user2, user3} {@debug user.firstname} {@debug myArray[0]} {@debug !isReady} {@debug typeof user === 'object'} ``` 引数なしの `{@debug}` タグは、特定の変数ではなく、_何らかの_ state が変化した際にトリガーされる `debugger` ステートメントを挿入します。 # bind: データは通常、親から子へと流れますが、`bind:` ディレクティブを使用すると、データを子から親へ流すことができます。 一般的な構文は `bind:property={expression}` であり、`expression` は [_lvalue_](https://press.rebus.community/programmingfundamentals/chapter/lvalue-and-rvalue/) (つまり、変数やオブジェクトのプロパティ) です。式がプロパティと同じ名前の識別子である場合、式を省略することができます — 言い換えると、以下は等価です: ```svelte ``` Svelte は、バインドされた値を更新するイベントリスナーを作成します。要素が既に同じイベントのリスナーを持っている場合、そのリスナーはバインドされた値が更新される前に実行されます。 ほとんどのバインディングは _双方向_ であり、値の変更が要素に影響し、その逆も同様です。一部のバインディングは _読み取り専用_ であり、値を変更しても要素に影響を与えません。 ## Function bindings `bind:property={get, set}` を使用して、`get` と `set` を関数として指定し、バリデーションや変換を行うことができます: ```svelte value, (v) => value = v.toLowerCase()} /> ``` [dimension bindings](#Dimensions) のような読み取り専用バインディングの場合、`get` の値は `null` にする必要があります: ```svelte ... ``` > [!NOTE] > Function bindings は Svelte 5.9.0 以降で使用可能です。 ## `` `` 要素に対する `bind:value` ディレクティブは、input の `value` プロパティをバインドします: ```svelte {message} ``` In the case of a numeric input (`type="number"` or `type="range"`), the value will be coerced to a number: ```svelte {a} + {b} = {a + b} ``` 入力が空または無効 (`type="number"` の場合) の場合、値は `undefined` になります。 バージョン 5.6.0 以降、`` に `defaultValue` が設定されていてフォームの一部である場合、フォームがリセットされると空文字列ではなくその値に戻ります。初回のレンダリングでは、バインディングの値が `null` または `undefined` でない限り優先されることに注意してください。 ```svelte ``` > [!NOTE] > リセットボタンは慎重に使用し、ユーザーがフォームを送信しようとしているときに誤ってクリックしないようにしてください。 ## `` checkbox input には、`bind:checked` を使用してバインドできます: ```svelte Accept terms and conditions ``` バージョン 5.6.0 以降、`` に `defaultChecked` 属性が設定されておりフォームの一部である場合、フォームがリセットされると `false` ではなくその値に戻ります。初回のレンダリングでは、バインディングの値が `null` または `undefined` でない限り優先されます。 ```svelte ``` > [!NOTE] radio input には、`bind:checked` ではなく `bind:group` を使用してください。 ## `` チェックボックスは、それがチェックされているかされていないかに関係なく、[indeterminate](https://developer.mozilla.org/ja/docs/Web/API/HTMLInputElement/indeterminate) 状態にすることができます: ```svelte {#if indeterminate} waiting... {:else if checked} checked {:else} unchecked {/if} ``` ## `` Inputs that work together can use `bind:group`: ```svelte Customize your burrito Plain Whole wheat Spinach Rice Beans Cheese Guac (extra) Tortilla: {tortilla} Fillings: {fillings.join(', ') || 'None'} ``` > [!NOTE] `bind:group` は、input が同じ Svelte コンポーネント内にある場合にのみ機能します。 ## `` `type="file"` を持つ `` 要素では、`bind:files` を使用して [選択されたファイルの `FileList`](https://developer.mozilla.org/ja/docs/Web/API/FileList) を取得できます。プログラムでファイルを更新する場合、常に `FileList` オブジェクトを使用する必要があります。現在、`FileList` オブジェクトは直接作成できないため、新しい [`DataTransfer`](https://developer.mozilla.org/ja/docs/Web/API/DataTransfer) オブジェクトを作成し、そこから `files` を取得する必要があります。 ```svelte Upload a picture: clear ``` `FileList` オブジェクトも変更できないため、例えばリストから単一のファイルを削除したい場合は、新しい `DataTransfer` オブジェクトを作成し、保持したいファイルを追加する必要があります。 > [!NOTE] `DataTransfer` はサーバーサイドの JS ランタイムでは利用できない場合があります。`files` にバインドされた state を未初期化のままにしておくことで、コンポーネントがサーバーサイドレンダリングされる際の潜在的なエラーを防ぐことができます。 ## `` `` の値のバインディングは、選択された `` の `value` プロパティに対応しており、これは通常の DOM での場合と異なり、文字列だけでなく任意の値を使用できます。 ```svelte a b c ``` `` 要素は、チェックボックスグループと同様に動作します。バインドされた変数は、選択された各 `` の `value` プロパティに対応するエントリを持つ配列です。 ```svelte Rice Beans Cheese Guac (extra) ``` `` の値がそのテキストコンテンツと一致する場合、その属性は省略できます。 ```svelte Rice Beans Cheese Guac (extra) ``` You can give the `` a default value by adding a `selected` attribute to the `` (or options, in the case of ``) that should be initially selected. If the `` is part of a form, it will revert to that selection when the form is reset. Note that for the initial render the value of the binding takes precedence if it's not `undefined`. ```svelte a b c ``` ## `` `` 要素には、以下の5つの双方向バインディングがあります: - [`currentTime`](https://developer.mozilla.org/ja/docs/Web/API/HTMLMediaElement/currentTime) - [`playbackRate`](https://developer.mozilla.org/ja/docs/Web/API/HTMLMediaElement/playbackRate) - [`paused`](https://developer.mozilla.org/ja/docs/Web/API/HTMLMediaElement/paused) - [`volume`](https://developer.mozilla.org/ja/docs/Web/API/HTMLMediaElement/volume) - [`muted`](https://developer.mozilla.org/ja/docs/Web/API/HTMLMediaElement/muted) ...および以下の6つの読み取り専用バインディングがあります: - [`duration`](https://developer.mozilla.org/ja/docs/Web/API/HTMLMediaElement/duration) - [`buffered`](https://developer.mozilla.org/ja/docs/Web/API/HTMLMediaElement/buffered) - [`seekable`](https://developer.mozilla.org/ja/docs/Web/API/HTMLMediaElement/seekable) - [`seeking`](https://developer.mozilla.org/ja/docs/Web/API/HTMLMediaElement/seeking_event) - [`ended`](https://developer.mozilla.org/ja/docs/Web/API/HTMLMediaElement/ended) - [`readyState`](https://developer.mozilla.org/ja/docs/Web/API/HTMLMediaElement/readyState) - [`played`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/played) ```svelte ``` ## `` `` 要素には、[``](#audio) 要素と同じバインディングがすべて含まれ、さらに読み取り専用の [`videoWidth`](https://developer.mozilla.org/ja/docs/Web/API/HTMLVideoElement/videoWidth) および [`videoHeight`](https://developer.mozilla.org/ja/docs/Web/API/HTMLVideoElement/videoHeight) バインディングがあります。 ## `` `` 要素には、以下の2つの読み取り専用バインディングがあります: - [`naturalWidth`](https://developer.mozilla.org/ja/docs/Web/API/HTMLImageElement/naturalWidth) - [`naturalHeight`](https://developer.mozilla.org/ja/docs/Web/API/HTMLImageElement/naturalHeight) ## `` `` 要素は、`open` プロパティへのバインディングをサポートします。 ```svelte How do you comfort a JavaScript bug? You console it. ``` ## `window` and `document` To bind to properties of `window` and `document`, see [``](svelte-window) and [``](svelte-document). ## Contenteditable bindings `contenteditable` 属性を持つ要素は、以下のバインディングをサポートします: - [`innerHTML`](https://developer.mozilla.org/ja/docs/Web/API/Element/innerHTML) - [`innerText`](https://developer.mozilla.org/ja/docs/Web/API/HTMLElement/innerText) - [`textContent`](https://developer.mozilla.org/ja/docs/Web/API/Node/textContent) > [!NOTE] [`innerText` と `textContent` には微妙な違いがあります](https://developer.mozilla.org/ja/docs/Web/API/Node/textContent#innertext_との違い)。 ```svelte ``` ## Dimensions すべての visible な要素には、以下の読み取り専用バインディングがあり、これらは `ResizeObserver` を使用して測定されます: - [`clientWidth`](https://developer.mozilla.org/ja/docs/Web/API/Element/clientWidth) - [`clientHeight`](https://developer.mozilla.org/ja/docs/Web/API/Element/clientHeight) - [`offsetWidth`](https://developer.mozilla.org/ja/docs/Web/API/HTMLElement/offsetWidth) - [`offsetHeight`](https://developer.mozilla.org/ja/docs/Web/API/HTMLElement/offsetHeight) - [`contentRect`](https://developer.mozilla.org/ja/docs/Web/API/ResizeObserverEntry/contentRect) - [`contentBoxSize`](https://developer.mozilla.org/ja/docs/Web/API/ResizeObserverEntry/contentBoxSize) - [`borderBoxSize`](https://developer.mozilla.org/ja/docs/Web/API/ResizeObserverEntry/borderBoxSize) - [`devicePixelContentBoxSize`](https://developer.mozilla.org/ja/docs/Web/API/ResizeObserverEntry/devicePixelContentBoxSize) ```svelte ``` > [!NOTE] `display: inline` 要素には width や height がありません (`` や `` のような「固有の」 dimension を持つ要素を除く)。そのため、`ResizeObserver` で観測することはできません。これらの要素の `display` スタイルを `inline-block` などに変更する必要があります。CSS transformation は `ResizeObserver` コールバックをトリガーしないことにご注意ください。 ## bind:this ```svelte bind:this={dom_node} ``` DOM ノードへの参照を取得するには、`bind:this` を使用します。この値はコンポーネントがマウントされるまで `undefined` のままです — 言い換えると、初期化時ではなく、effect やイベントハンドラー内で読み取る必要があります: ```svelte ``` コンポーネントも `bind:this` をサポートしており、プログラムでコンポーネントインスタンスを操作できます。 ```svelte cart.empty()}> Empty shopping cart ``` ```svelte ``` > [!NOTE] In case of using [the function bindings](#Function-bindings), the getter is required to ensure that the correct value is nullified on component or element destruction. ## bind:_property_ for components ```svelte bind:property={variable} ``` 要素と同じ構文を使用して、コンポーネントの props にバインドできます。 ```svelte ``` Svelte の props はバインディングなしでもリアクティブですが、そのリアクティビティはデフォルトでコンポーネント内にのみ流れます。`bind:property` を使用すると、コンポーネント内から props の変更をコンポーネント外に流すことができます。 props がバインド可能なものとしてマークするには、[`$bindable`]($bindable) rune を使用します: ```svelte ``` props をバインド可能として宣言することは、それが `bind:` を使用できることを意味しますが、`bind:` を使用しなければならないことを意味するわけではありません。 bindable な props にはフォールバック値を設定できます: ```svelte ``` このフォールバック値は、props がバインドされていない場合にのみ適用されます。props がバインドされていてフォールバック値が存在する場合、親コンポーネントは `undefined` 以外の値を提供する必要があります。そうでない場合、ランタイムエラーが発生します。これにより、どの値が適用されるかが不明確な状況になるのを防ぎます。 # use: > [!NOTE] > Svelte 5.29 以上の場合、代わりに [attachments](@attach) の使用をご検討ください。よりフレキシブルでコンポーザブルです。 action は、要素がマウントされたときに呼び出される関数です。これらは `use:` ディレクティブを使用して追加され、通常は `$effect` を使用して、要素がアンマウントされたときに state をリセットします: ```svelte ... ``` action には引数を渡すことができます: ```svelte ... ``` action は一度だけ呼び出されます (サーバーサイドレンダリング時には呼び出されません) — 引数が変更されても再実行されることはありません。 > [!LEGACY] > `$effect` rune が導入される前は、action は `update` と `destroy` メソッドを持つオブジェクトを返すことができました。この場合、引数が変更されると `update` が最新の値で呼び出されました。現在は effect の使用が推奨されています。 ## 型付け `Action` インターフェースは、3つのオプションの型引数を受け取ります — ノードの型 (action がすべての要素に適用される場合は `Element` にできます)、パラメーター、および action によって作成されるカスタムイベントハンドラーです: ```svelte ... ``` # transition: _transition_ は、state の変化の結果として DOM に要素が出入りする際にトリガーされます。 ブロック (例えば `{#if ...}` ブロック) が外へ transition している間、その中のすべての要素 (独自の transition を持たないものも含む) は、ブロック内のすべての transition が完了するまで DOM に保持されます。 `transition:` ディレクティブは _双方向_ transition を示します。これにより、transition の進行中でもスムーズに反転させることができることを意味しています。 ```svelte visible = !visible}>toggle {#if visible} fades in and out {/if} ``` ## Local vs global transition はデフォルトで local です。local transition は、それが属するブロックが作成または破棄されるときにのみ実行され、親ブロックが作成または破棄されるときには実行されません。 ```svelte {#if x} {#if y} fades in and out only when y changes fades in and out when x or y change {/if} {/if} ``` ## Built-in transitions A selection of built-in transitions can be imported from the [`svelte/transition`](svelte-transition) module. ## Transition parameters transition にはパラメータを指定することができます。 (二重の `{{中括弧}}` は特別な構文ではありません。これは式タグ内のオブジェクトリテラルです。) ```svelte {#if visible} fades in and out over two seconds {/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 } ``` transition にはカスタム関数を使用することができます。返されるオブジェクトに `css` 関数が含まれている場合、Svelte は [web animation](https://developer.mozilla.org/ja/docs/Web/API/Web_Animations_API) のキーフレームを生成します。 `css` に渡される `t` 引数は、`easing` 関数が適用された後の `0` から `1` の間の値です。_in_ transition は `0` から `1` に進行し、_out_ transition は `1` から `0` に進行します — 言い換えると、`1` は transition が適用されていない要素の自然な状態です。`u` 引数は `1 - t` に等しい値です。 この関数は、transition が開始される前に、異なる `t` および `u` 引数とともに繰り返し呼び出されます。 ```svelte {#if visible} whooshes in {/if} ``` カスタムの transition 関数は、transition の途中で同じ `t` と `u` の引数と共に呼び出される `tick` 関数を返すこともできます。 > [!NOTE] `tick` の代わりに `css` を使用できる場合は、そうしてください — web animation はメインスレッドの外で実行されるため、低速なデバイスでのカクつきを防ぐことができます。 ```svelte {#if visible} The quick brown fox jumps over the lazy dog {/if} ``` transition が transition オブジェクトの代わりに関数を返す場合、その関数は次のマイクロタスク内で呼び出されます。これにより、複数の transition が調整され、[クロスフェード効果](/tutorial/deferred-transitions) を実現できます。 transition 関数は、transition に関する情報を含む第3引数 `options` を受け取ります。 `options` オブジェクトで使用可能な値は以下の通りです: - `direction` - transition のタイプに応じて `in`、`out`、`both` のいずれか ## Transition events transition を持つ要素は、標準の DOM イベントに加えて次のイベントをディスパッチします: - `introstart` - `introend` - `outrostart` - `outroend` ```svelte {#if visible} (status = 'intro started')} onoutrostart={() => (status = 'outro started')} onintroend={() => (status = 'intro ended')} onoutroend={() => (status = 'outro ended')} > Flies in and out {/if} ``` # in: and out: `in:` ディレクティブと `out:` ディレクティブは [`transition:`](transition) と同じですが、`in:` と `out:` の場合は双方向でない点が異なります — transition の進行中にブロックが消される場合、`in` transition は反転するのでなく、`out` transition と一緒に再生され続けます。`out` transition が中止されると、transition は最初からやり直されます。 ```svelte visible {#if visible} flies in, fades out {/if} ``` # animate: [keyed each block](each#Keyed-each-blocks) のコンテンツが並べ替えられると、アニメーションがトリガーされます。アニメーションは要素が追加または削除されたときには実行されず、each ブロック内の既存データ項目のインデックスが変更された場合にのみ実行されます。animate ディレクティブは、keyed each ブロックの _直下_ にある要素に付ける必要があります。 アニメーションは、Svelte の [組み込みアニメーション関数](svelte-animate) または [カスタムアニメーション関数](#Custom-animation-functions) を使用して実現できます。 ```svelte {#each list as item, index (item)} {item} {/each} ``` ## Animation Parameters action や transition と同様に、アニメーションにもパラメータを設定することができます。 (二重の `{{curlies}}` は特別な構文ではありません。これは式タグ内のオブジェクトリテラルです。) ```svelte {#each list as item, index (item)} {item} {/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 } ``` アニメーションには、`node`、`animation` オブジェクト、および任意の `parameters` を引数として提供するカスタム関数を使用することができます。`animation` パラメータは、要素の `start` と `end` の位置を記述した [DOMRect](https://developer.mozilla.org/en-US/docs/Web/API/DOMRect#Properties) を含む `from` および `to` プロパティを持つオブジェクトです。`from` プロパティは要素の開始位置を表す DOMRect で、`to` プロパティはリストが並べ替えられて DOM が更新された後の要素の最終位置を表す DOMRect です。 返されたオブジェクトに `css` メソッドがある場合、Svelte は要素上で再生される [web animation](https://developer.mozilla.org/ja/docs/Web/API/Web_Animations_API) を作成します。 `css` に渡される `t` 引数は、`easing` 関数が適用された後に `0` から `1` に変化する値です。`u` 引数は `1 - t` に等しい値です。 この関数は、アニメーションが開始する前に異なる `t` および `u` 引数で繰り返し呼び出されます。 ```svelte {#each list as item, index (item)} {item} {/each} ``` カスタムアニメーション関数は `tick` 関数を返すことも可能で、これはアニメーション中に同じ `t` および `u` 引数で呼び出されます。 > [!NOTE] `tick` の代わりに `css` を使用できる場合はそうしてください — web animation はメインスレッド外で実行できるため、遅いデバイスでのカクつきを防ぐことができます。 ```svelte {#each list as item, index (item)} {item} {/each} ``` # style: `style:` ディレクティブは、1つの要素に複数のスタイルを設定するための短縮形の記法を提供します。 ```svelte ... ... ``` 値には任意の式を含めることができます: ```svelte ... ``` 短縮形の形式も使用可能です: ```svelte ... ``` 1つの要素に複数のスタイルを設定することができます: ```svelte ... ``` スタイルを important としてマークするには、`|important` 修飾子を使用します: ```svelte ... ``` `style:` ディレクティブが `style` 属性と組み合わせて使用される場合、ディレクティブが優先されます、 たとえ `!important` プロパティが指定されていてもです: ```svelte This will be red This will still be red ``` You can set CSS custom properties: ```svelte ... ``` # class 要素にクラスを設定する方法は2つあります: `class` 属性と `class:` ディレクティブです。 ## Attributes プリミティブな値は他の属性と同じように扱われます: ```svelte ... ``` > [!NOTE] > 歴史的な理由により、falsy な値 (例えば `false` や `NaN`) は文字列化されます (`class="false"`) が、`class={undefined}` (または `null`) の場合、属性が完全に省略されます。将来の Svelte バージョンでは、すべての falsy の値で `class` が省略されるようになります。 ### Objects and arrays Svelte 5.16以降、`class` はオブジェクトや配列で指定でき、[clsx](https://github.com/lukeed/clsx) で文字列に変換されます。 値がオブジェクトの場合、truthy なキーが追加されます: ```svelte ... ``` 値が配列の場合、truthy な値が結合されます: ```svelte ... ``` 配列形式でもオブジェクト形式でも、1つの条件で複数のクラスを同時に設定できます。これは、Tailwind のようなものを使用している場合に特に便利です。 配列は配列やオブジェクトを含むことができ、clsx がそれらをフラットにします。例えば、ローカルクラスと props を組み合わせる際に便利です: ```svelte {@render props.children?.()} ``` このコンポーネントのユーザーは、オブジェクト、配列、文字列を混在させる柔軟性を得ることができます: ```svelte useTailwind = true} class={{ 'bg-blue-700 sm:w-1/2': useTailwind }} > Accept the inevitability of Tailwind ``` Svelte 5.19 から、Svelte では要素の `class` 属性が受け入れる値の型である `ClassValue` 型も公開しています。これは、コンポーネントの props に型安全なクラス名を使用したい場合に便利です: ```svelte ... ``` ## The `class:` directive Svelte 5.16以前では、`class:` ディレクティブは条件付きで要素にクラスを設定する最も便利な方法でした。 ```svelte ... ... ``` 他のディレクティブと同様に、クラス名が値と一致する場合は短縮形を使用できます: ```svelte ... ``` > [!NOTE] 古いバージョンの Svelte を使用していない限り、`class:` を避けることを検討してください。属性の方がより強力でコンポーザブル (composable) だからです。 # await Svelte5.36 以降、コンポーネント内のうち、これまで使えなかった3箇所で `await` キーワードを使えるようになりました: - コンポーネントの ` {a} + {b} = {await add(a, b)} ``` ...`a` の値をインクリメントしても、 `` の内容は次のようには _なりません。_ ```html 2 + 2 = 3 ``` 実際には、`add(a, b)`が解決されたときに、``の内容を `2 + 2 = 4` に更新します。 更新は重複することがあります。先行する更新が遅く、まだ進行中であっても、続く更新が速ければ、速いほうが先にUIに反映されます。 ## 並行性 Svelte は可能な限り非同期処理を並行におこないます。例えば、マークアップ内に2つの `await` 式があるとき... ```svelte {await one(x)} {await two(y)} ``` ...それらは独立した式ですので、 _見た目上は_ 順次実行されているように見えても、両方の関数が同時に実行されます。 これは、` { pending?.commit(); pending = null; // in case `pending` didn't exist // (if it did, this is a no-op) open = true; }} >open menu {#if open} open = false} /> {/if} ``` ## 注意事項 実験的な機能であるため、 `await` 扱いの詳細(および `$effect.pending()` のような関連API)は、セマンティックバージョニングのメジャーリリース外では破壊的変更がおこなわれる可能性があります。ただし、そのような変更は最小限に抑えるつもりです。 ## 破壊的変更 `experimental.async` オプションが `true` のとき、効果の実行順序がわずかに異なります。具体的には、 `{#if ...}` や `{#each ...}` のような _ブロック_ の効果を、 `$effect.pre` や `beforeUpdate` の前に実行するようになります。これにより、非常にまれな状況。 # Scoped styles Svelte コンポーネントには、そのコンポーネント専用の CSS を置くための ` ``` ## 詳細度(Specificity) スコープされた各セレクタは、スコープ用クラス (例: `.svelte-123xyz`) がセレクタに追加されることで、[詳細度(specificity)](https://developer.mozilla.org/ja/docs/Web/CSS/Specificity) が 0-1-0 増加します。つまり、コンポーネント内で定義された `p` セレクタは、グローバルなスタイルシートで定義された `p` セレクタよりも優先されます。たとえグローバルなスタイルシートが後から読み込まれたとしてもです。 一部のケースでは、スコープ用クラスをセレクタに複数回追加する必要がありますが、2回目以降は `:where(.svelte-xyz123)` を使用して追加されます。これは詳細度をさらに増加させないためです。 ## Scoped keyframes コンポーネントが `@keyframes` を定義した場合、その name は同じハッシュ手法を使用してコンポーネントにスコープされます。コンポーネント内の `animation` ルールも同様に調整されます。 ```svelte ``` # Global styles ## :global(...) 単一のセレクターに対してグローバルにスタイルを適用するには、`:global(...)` 修飾子を使用します: ```svelte ``` @keyframes をグローバルにアクセス可能にしたい場合は、keyframe name の前に `-global-` を付ける必要があります。 `-global-` の部分はコンパイル時に削除され、その後はコード内のどこからでも `my-animation-name` という名前でその keyframe を参照できるようになります。 ```svelte ``` ## :global 一連のセレクターに対してグローバルにスタイルを適用するには、`:global {...}` ブロックを作成します: ```svelte ``` > [!NOTE] 上記の 2 番目の例は `.a :global .b .c .d` セレクターとしても記述でき、この場合は `:global` の後に続く部分がスコープされません。なお、ネスト形式の方が推奨されます。 # Custom properties コンポーネントに CSS のカスタムプロパティを渡すことができます。静的なものも動的なものも可能です: ```svelte ``` 上記のコードは、本質的には次のように脱糖(desugar)されます: ```svelte ``` SVG 要素の場合、代わりに `` が使用されます: ```svelte ``` コンポーネント内では、[`var(...)`](https://developer.mozilla.org/ja/docs/Web/CSS/Using_CSS_custom_properties) を使用してこれらのカスタムプロパティを読み取ることができ、またフォールバック値を指定することができます: ```svelte ``` カスタムプロパティの値をコンポーネントに直接指定する _必要はありません_。親要素にカスタムプロパティが定義されていれば、コンポーネントはそれを使用できます。アプリケーション全体に適用するために、グローバルスタイルシートの `:root` 要素でカスタムプロパティを定義するのが一般的です。 > [!NOTE] 追加される要素はレイアウトには影響しませんが、例えば `>` コンビネータを使用してコンポーネントのコンテナ内の要素を直接ターゲットにする CSS セレクタには影響を与えます。 # Nested ` ``` # `` ```svelte ... ``` > [!NOTE] > この機能は 5.3.0 で追加されました boundary (境界) を使用すると、アプリの一部で発生したエラーがアプリ全体を壊すのを防ぎ、それらのエラーから回復することができます。 `` 内の子要素をレンダリングまたは更新するとき、あるいはそれに含まれる [`$effect`]($effect) 関数の実行中にエラーが発生すると、そのコンテンツは削除されます。 レンダリングプロセスの外で発生するエラー (例えば、イベントハンドラー内で発生するエラーや、`setTimeout`や非同期処理の後のエラー) は error boundary では捕捉されません。 ## プロパティ boundary を機能させるには、以下のうち、1つ以上を提供する必要があります。 ### `pending` This snippet will be shown when the boundary is first created, and will remain visible until all the [`await`](await-expressions) expressions inside the boundary have resolved (demo: ```svelte {await delayed('hello!')} {#snippet pending()} loading... {/snippet} ``` `pending` snippet は、後続の非同期更新では表示されません — これについては、[`$effect.pending()`]($effect#$effect.pending) を使用できます。 > [!NOTE] [playground]では、空の pending snippet を持つ boundary 内でアプリがレンダリングされるため、boundary を作成せずに `await` を使用できます。 ### `failed` `failed` snippet が提供される場合、それは boundary 内でエラーがスローされたときにレンダリングされます。`failed` snippet にはその `error` と、コンテンツを再作成する `reset` 関数が引数として渡されます (デモ。 ```svelte {#snippet failed(error, reset)} oops! try again {/snippet} ``` > [!NOTE] > [コンポーネントに渡される snippet](snippet#Passing-snippets-to-components) と同様に、`failed` snippet はプロパティとして明示的に渡すことができます... > > ```svelte > ... > ``` > > ...または、上記の例のように boundary 内に直接記述することで暗黙的に渡すこともできます。 ### `onerror` `onerror` 関数が提供されると、`failed` と同じ `error` と `reset` の2つの引数とともに呼び出されます。これはエラーレポートサービスでエラーを追跡するのに役立ちます... ```svelte report(e)}> ... ``` ...または、`error` と `reset` を boundary の外部で使用することもできます: ```svelte {#if error} { error = null; reset(); }}> oops! try again {/if} ``` If an error occurs inside the `onerror` function (or if you rethrow the error), it will be handled by a parent boundary if such exists. ## Using `transformError` By default, error boundaries have no effect on the server — if an error occurs during rendering, the render as a whole will fail. Since 5.51 you can control this behaviour for boundaries with a `failed` snippet, by calling [`render(...)`](imperative-component-api#render) with a `transformError` function. > [!NOTE] If you're using Svelte via a framework such as SvelteKit, you most likely don't have direct access to the `render(...)` call — the framework must configure `transformError` on your behalf. SvelteKit will add support for this in the near future, via the [`handleError`](../kit/hooks#Shared-hooks-handleError) hook. The `transformError` function must return a JSON-stringifiable object which will be used to render the `failed` snippet. This object will be serialized and used to hydrate the snippet in the browser: ```js // @errors: 1005 import { render } from 'svelte/server'; import App from './App.svelte'; const { head, body } = await render(App, { transformError: (error) => { // log the original error, with the stack trace... console.error(error); // ...and return a sanitized user-friendly error // to display in the `failed` snippet return { message: 'An error occurred!' }; }; }); ``` If `transformError` throws (or rethrows) an error, `render(...)` as a whole will fail with that error. > [!NOTE] Errors that occur during server-side rendering can contain sensitive information in the `message` and `stack`. It's recommended to redact these rather than sending them unaltered to the browser. If the boundary has an `onerror` handler, it will be called upon hydration with the deserialized error object. The [`mount`](imperative-component-api#mount) and [`hydrate`](imperative-component-api#hydrate) functions also accept a `transformError` option, which defaults to the identity function. As with `render`, this function transforms a render-time error before it is passed to a `failed` snippet or `onerror` handler. # `` ```svelte ``` ```svelte ``` `` 要素を使用すると、コンポーネントが破棄される際にイベントリスナーを削除する手間や、サーバーサイドレンダリング時に `window` の存在を確認する必要がなく、`window` オブジェクトにイベントリスナーを追加することができます。 この要素はコンポーネントのトップレベルにのみ配置できます — ブロックや他の要素の中に含めることはできません。 ```svelte ``` 以下のプロパティにもバインドできます: - `innerWidth` - `innerHeight` - `outerWidth` - `outerHeight` - `scrollX` - `scrollY` - `online` — an alias for `window.navigator.onLine` - `devicePixelRatio` `scrollX` と `scrollY` を除くすべてのプロパティは読取専用です。 ```svelte ``` > [!NOTE] アクセシビリティの問題を避けるため、ページは初期値にスクロールされません。`scrollX` や `scrollY` にバインドされた変数の変更があった場合のみスクロールが発生します。コンポーネントがレンダリングされたときにスクロールを発生させる正当な理由がある場合は、`$effect` 内で `scrollTo()` を呼び出してください。 # `` ```svelte ``` ```svelte ``` Similarly to ``, 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 [attachments](@attach) on `document`. `` と同様に、この要素はコンポーネントのトップレベルにのみ配置でき、ブロックや他の要素の中に含めることはできません。 ```svelte ``` 以下のプロパティにもバインドできます: - `activeElement` - `fullscreenElement` - `pointerLockElement` - `visibilityState` すべて読取専用です。 # `` ```svelte ``` `` と似ていますが、この要素では、`window` では発火しない `mouseenter` や `mouseleave` などの `document.body` のイベントにリスナーを追加することができます。また、`` 要素で [action](use) を使用することもできます。 `` や `` と同様に、この要素はコンポーネントのトップレベルにのみ配置でき、ブロックや他の要素の中に含めることはできません。 ```svelte ``` # `` ```svelte ... ``` この要素を使用すると、`document.head` 内に要素を挿入できます。サーバーサイドレンダリング時には、`head` の内容は `body` の主要なコンテンツとは別に出力されます。 ``、``、`` と同様に、この要素はコンポーネントのトップレベルにのみ配置でき、ブロックや他の要素の中に含めることはできません。 ```svelte Hello world! ``` # `` ```svelte ``` `` 要素を使用すると、開発中には不明な要素 (例えば CMS から提供される要素) をレンダリングできます。プロパティやイベントリスナーを指定した場合は、その要素に適用されます。 Svelte の組み込みバインディングはジェネリックな要素には対応していないため、唯一サポートされているバインディングは `bind:this` です。 `this` に nullish な値が設定されている場合、その要素とその子要素はレンダリングされません。 `this` に [void element(空要素)](https://developer.mozilla.org/ja/docs/Glossary/Void_element) (例えば `br`) のタグ名が指定されており、`` に子要素が含まれている場合、開発モードの場合は実行時エラーが発生します: ```svelte This text cannot appear inside an hr element ``` Svelte は可能な限り要素の周囲の状況から適切な名前空間を推測しようとしますが、常に正しく推測できるとは限りません。そのため、`xmlns` 属性を使用して明示的に指定することができます: ```svelte ``` `this` には有効な DOM 要素のタグを指定する必要があります。例えば `#text` や `svelte:head` などは使用できません。 # `` ```svelte ``` `` 要素を使用すると、コンポーネントごとのコンパイラオプションを指定できます。詳細は [コンパイラのセクション](svelte-compiler#compile) に記載されています。使用可能なオプションは以下のとおりです: - `runes={true}` — コンポーネントを _runes モード_ に強制します ([Legacy APIs](legacy-overview) セクションを参照) - `runes={false}` — コンポーネントを _レガシーモード_ に強制します - `namespace="..."` — このコンポーネントが使用される名前空間を指定します。デフォルトは "html" で、"svg" や "mathml" も指定可能です。 - `customElement={...}` — このコンポーネントを custom element としてコンパイルする際に使用する [オプション](custom-elements#Component-options) を指定します。文字列を渡すと、それが `tag` オプションとして使用されます。 - `css="injected"` — コンポーネントのスタイルをインラインで挿入します。サーバーサイドレンダリング時には `head` 内に ` ``` If this is impossible (for example, the child component comes from a library) you can use `:global` to override styles: ```svelte ``` ## Context Consider using context instead of declaring state in a shared module. This will scope the state to the part of the app that needs it, and eliminate the possibility of it leaking between users when server-side rendering. Use `createContext` rather than `setContext` and `getContext`, as it provides type safety. ## Async Svelte If using version 5.36 or higher, you can use [await expressions](await-expressions) and [hydratable](hydratable) to use promises directly inside components. Note that these require the `experimental.async` option to be enabled in `svelte.config.js` as they are not yet considered fully stable. ## Avoid legacy features Always use runes mode for new code, and avoid features that have more modern replacements: - use `$state` instead of implicit reactivity (e.g. `let count = 0; count += 1`) - use `$derived` and `$effect` instead of `$:` assignments and statements (but only use effects when there is no better solution) - use `$props` instead of `export let`, `$$props` and `$$restProps` - use `onclick={...}` instead of `on:click={...}` - use `{#snippet ...}` and `{@render ...}` instead of `` and `$$slots` and `` - use `` instead of `` - use `import Self from './ThisComponent.svelte'` and `` instead of `` - use classes with `$state` fields to share reactivity between components, instead of using stores - use `{@attach ...}` instead of `use:action` - use clsx-style arrays and objects in `class` attributes, instead of the `class:` directive # Testing Testing helps you write and maintain your code and guard against regressions. Testing frameworks help you with that, allowing you to describe assertions or expectations about how your code should behave. Svelte is unopinionated about which testing framework you use — you can write unit tests, integration tests, and end-to-end tests using solutions like [Vitest](https://vitest.dev/), [Jasmine](https://jasmine.github.io/), [Cypress](https://www.cypress.io/) and [Playwright](https://playwright.dev/). ## Unit and component tests with Vitest Unit tests allow you to test small isolated parts of your code. Integration tests allow you to test parts of your application to see if they work together. If you're using Vite (including via SvelteKit), we recommend using [Vitest](https://vitest.dev/). You can use the Svelte CLI to [setup Vitest](/docs/cli/vitest) either during project creation or later on. To setup Vitest manually, first install it: ```sh npm install -D vitest ``` Then adjust your `vite.config.js`: ```js /// file: vite.config.js import { defineConfig } from +++'vitest/config'+++; export default defineConfig({ // ... // Tell Vitest to use the `browser` entry points in `package.json` files, even though it's running in Node resolve: process.env.VITEST ? { conditions: ['browser'] } : undefined }); ``` > [!NOTE] If loading the browser version of all your packages is undesirable, because (for example) you also test backend libraries, [you may need to resort to an alias configuration](https://github.com/testing-library/svelte-testing-library/issues/222#issuecomment-1909993331) You can now write unit tests for code inside your `.js/.ts` files: ```js /// file: multiplier.svelte.test.js // @filename: multiplier.svelte.ts export function multiplier(initial: number, k: number) { let count = $state(initial); return { get value() { return count * k; }, set: (c: number) => { count = c; } }; } // @filename: multiplier.svelte.test.js // ---cut--- import { flushSync } from 'svelte'; import { expect, test } from 'vitest'; import { multiplier } from './multiplier.svelte.js'; test('Multiplier', () => { let double = multiplier(0, 2); expect(double.value).toEqual(0); double.set(5); expect(double.value).toEqual(10); }); ``` ```js /// file: multiplier.svelte.js /** * @param {number} initial * @param {number} k */ export function multiplier(initial, k) { let count = $state(initial); return { get value() { return count * k; }, /** @param {number} c */ set: (c) => { count = c; } }; } ``` ### Using runes inside your test files Since Vitest processes your test files the same way as your source files, you can use runes inside your tests as long as the filename includes `.svelte`: ```js /// file: multiplier.svelte.test.js // @filename: multiplier.svelte.ts export function multiplier(getCount: () => number, k: number) { return { get value() { return getCount() * k; } }; } // @filename: multiplier.svelte.test.js // ---cut--- import { flushSync } from 'svelte'; import { expect, test } from 'vitest'; import { multiplier } from './multiplier.svelte.js'; test('Multiplier', () => { let count = $state(0); let double = multiplier(() => count, 2); expect(double.value).toEqual(0); count = 5; expect(double.value).toEqual(10); }); ``` ```js /// file: multiplier.svelte.js /** * @param {() => number} getCount * @param {number} k */ export function multiplier(getCount, k) { return { get value() { return getCount() * k; } }; } ``` If the code being tested uses effects, you need to wrap the test inside `$effect.root`: ```js /// file: logger.svelte.test.js // @filename: logger.svelte.ts export function logger(fn: () => void) {} // @filename: logger.svelte.test.js // ---cut--- import { flushSync } from 'svelte'; import { expect, test } from 'vitest'; import { logger } from './logger.svelte.js'; test('Effect', () => { const cleanup = $effect.root(() => { let count = $state(0); // logger uses an $effect to log updates of its input let log = logger(() => count); // effects normally run after a microtask, // use flushSync to execute all pending effects synchronously flushSync(); expect(log).toEqual([0]); count = 1; flushSync(); expect(log).toEqual([0, 1]); }); cleanup(); }); ``` ```js /// file: logger.svelte.js /** * @param {() => any} getValue */ export function logger(getValue) { /** @type {any[]} */ let log = []; $effect(() => { log.push(getValue()); }); return log; } ``` ### Component testing It is possible to test your components in isolation, which allows you to render them in a browser (real or simulated), simulate behavior, and make assertions, without spinning up your whole app. > [!NOTE] Before writing component tests, think about whether you actually need to test the component, or if it's more about the logic _inside_ the component. If so, consider extracting out that logic to test it in isolation, without the overhead of a component. To get started, install jsdom (a library that shims DOM APIs): ```sh npm install -D jsdom ``` Then adjust your `vite.config.js`: ```js /// file: vite.config.js import { defineConfig } from 'vitest/config'; export default defineConfig({ plugins: [ /* ... */ ], test: { // If you are testing components client-side, you need to set up a DOM environment. // If not all your files should have this environment, you can use a // `// @vitest-environment jsdom` comment at the top of the test files instead. environment: 'jsdom' }, // Tell Vitest to use the `browser` entry points in `package.json` files, even though it's running in Node resolve: process.env.VITEST ? { conditions: ['browser'] } : undefined }); ``` After that, you can create a test file in which you import the component to test, interact with it programmatically and write expectations about the results: ```js /// file: component.test.js import { flushSync, mount, unmount } from 'svelte'; import { expect, test } from 'vitest'; import Component from './Component.svelte'; test('Component', () => { // Instantiate the component using Svelte's `mount` API const component = mount(Component, { target: document.body, // `document` exists because of jsdom props: { initial: 0 } }); expect(document.body.innerHTML).toBe('0'); // Click the button, then flush the changes so you can synchronously write expectations document.body.querySelector('button')?.click(); flushSync(); expect(document.body.innerHTML).toBe('1'); // Remove the component from the DOM unmount(component); }); ``` While the process is very straightforward, it is also low level and somewhat brittle, as the precise structure of your component may change frequently. Tools like [@testing-library/svelte](https://testing-library.com/docs/svelte-testing-library/intro/) can help streamline your tests. The above test could be rewritten like this: ```js // @errors: 2339 /// file: component.test.js import { render, screen } from '@testing-library/svelte'; import userEvent from '@testing-library/user-event'; import { expect, test } from 'vitest'; import Component from './Component.svelte'; test('Component', async () => { const user = userEvent.setup(); render(Component); const button = screen.getByRole('button'); expect(button).toHaveTextContent(0); await user.click(button); expect(button).toHaveTextContent(1); }); ``` When writing component tests that involve two-way bindings, context or snippet props, it's best to create a wrapper component for your specific test and interact with that. `@testing-library/svelte` contains some [examples](https://testing-library.com/docs/svelte-testing-library/example). ## Component tests with Storybook [Storybook](https://storybook.js.org) is a tool for developing and documenting UI components, and it can also be used to test your components. They're run with Vitest's browser mode, which renders your components in a real browser for the most realistic testing environment. To get started, first install Storybook ([using Svelte's CLI](/docs/cli/storybook)) in your project via `npx sv add storybook` and choose the recommended configuration that includes testing features. If you're already using Storybook, and for more information on Storybook's testing capabilities, follow the [Storybook testing docs](https://storybook.js.org/docs/writing-tests?renderer=svelte) to get started. You can create stories for component variations and test interactions with the [play function](https://storybook.js.org/docs/writing-tests/interaction-testing?renderer=svelte#writing-interaction-tests), which allows you to simulate behavior and make assertions using the Testing Library and Vitest APIs. Here's an example of two stories that can be tested, one that renders an empty LoginForm component and one that simulates a user filling out the form: ```svelte /// file: LoginForm.stories.svelte { // Simulate a user filling out the form await userEvent.type(canvas.getByTestId('email'), 'email@provider.com'); await userEvent.type(canvas.getByTestId('password'), 'a-random-password'); await userEvent.click(canvas.getByRole('button')); // Run assertions await expect(args.onSubmit).toHaveBeenCalledTimes(1); await expect(canvas.getByText('You’re in!')).toBeInTheDocument(); }} /> ``` ## End-to-end tests with Playwright E2E (short for 'end to end') tests allow you to test your full application through the eyes of the user. This section uses [Playwright](https://playwright.dev/) as an example, but you can also use other solutions like [Cypress](https://www.cypress.io/) or [NightwatchJS](https://nightwatchjs.org/). You can use the Svelte CLI to [setup Playwright](/docs/cli/playwright) either during project creation or later on. You can also [set it up with `npm init playwright`](https://playwright.dev/docs/intro). Additionally, you may also want to install an IDE plugin such as [the VS Code extension](https://playwright.dev/docs/getting-started-vscode) to be able to execute tests from inside your IDE. If you've run `npm init playwright` or are not using Vite, you may need to adjust the Playwright config to tell Playwright what to do before running the tests — mainly starting your application at a certain port. For example: ```js /// file: playwright.config.js const config = { webServer: { command: 'npm run build && npm run preview', port: 4173 }, testDir: 'tests', testMatch: /(.+\.)?(test|spec)\.[jt]s/ }; export default config; ``` You can now start writing tests. These are totally unaware of Svelte as a framework, so you mainly interact with the DOM and write assertions. ```js // @errors: 2307 7031 /// file: tests/hello-world.spec.js import { expect, test } from '@playwright/test'; test('home page has expected h1', async ({ page }) => { await page.goto('/'); await expect(page.locator('h1')).toBeVisible(); }); ``` # TypeScript Svelte コンポーネント内で TypeScript を使えます。[Svelte VS Code 拡張機能](https://marketplace.visualstudio.com/items?itemName=svelte.svelte-vscode)のようなIDE拡張機能はエディタ上でエラーをキャッチするのに役立ちます。また、 [`svelte-check`](https://www.npmjs.com/package/svelte-check) はコマンドラインで同じことができ、CIに統合できます。 ## ` greet(e.target.innerText)}> {name as string} ``` これにより、 TypeScript の機能のうち _型のみ_ 使えます。つまり、型アノテーションやインターフェース宣言など、 JavaScript にトランスコンパイルすると消えてしまうすべての機能です。 TypeScript コンパイラが実際のコードを出力する必要のある機能はサポートされていません。これには以下が含まれます: - enumの使用 - コンストラクタ関数で `private`、 `protected` 、 `public` 修飾子を初期化子(initializer)といっしょに使用する - ECMAScript 標準の一部ではない(つまりTC39プロセスでレベル4ではない)ため、 JavaScript 解析に用いるパーサー Acorn 内に実装されていない機能の使用 これらいずれかの機能を使いたいときは、 `script` プリプロセッサをセットアップする必要があります。 ## プリプロセッサのセットアップ Svelte コンポーネント内で型以外の TypeScript 機能を使うには、 TypeScript を JavaScript に変換するプリプロセッサを追加する必要があります。 ### Using Vite If you're using SvelteKit, or Vite _without_ SvelteKit, you can use `vitePreprocess` from `@sveltejs/vite-plugin-svelte` in your config file: ```ts /// file: svelte.config.js // @noErrors import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'; const config = { // `{ script: true }` の追加に注目してください preprocess: vitePreprocess({ script: true }) }; export default config; ``` ### Using other build tools If you're using tools like Rollup (via [rollup-plugin-svelte](https://github.com/sveltejs/rollup-plugin-svelte)) or Webpack (via [svelte-loader](https://github.com/sveltejs/svelte-loader)) instead, install `typescript` and `svelte-preprocess` and add the preprocessor to the plugin config. See the respective plugin READMEs for more info. > [!NOTE] 新しいプロジェクトを開始するときは、代わりに SvelteKit または Vite の使用をおすすめします。 ## tsconfig.json の設定 TypeScript を使うときは、 `tsconfig.json` が正しく設定されていることを確認してください。 - クラスが関数にコンパイルされないように、 [`target`](https://www.typescriptlang.org/tsconfig/#target) を少なくとも `ES2015` 以降に設定してください。 - インポートがそのまま残るように、 [`verbatimModuleSyntax`](https://www.typescriptlang.org/tsconfig/#verbatimModuleSyntax) を `true` に設定してください。 - 各ファイルが個別に扱われるように、 [`isolatedModules`](https://www.typescriptlang.org/tsconfig/#isolatedModules) を `true` に設定してください。 TypeScript にはファイル間解析とコンパイルを必要とする機能がいくつかありますが、 Svelte コンパイラや Vite などのツールではこれをおこないません。 ## `$props` の型付け `$props` を、特定のプロパティを持つ通常のオブジェクトと同じように型付けします。 ```svelte eventHandler('clicked button')}> {@render snippetWithStringArgument('hello')} ``` ## ジェネリックな $props コンポーネントのプロパティ間で、ジェネリクス(generics)を用いて型を関連づけることができます。例えば、汎用的なリストコンポーネントを考えてみましょう。このコンポーネントには、プロパティとして「アイテムのリスト」と「リストからアイテムを1つ受け取るコールバック関数」を渡すことができます。 そして、この `items` プロパティ(の配列)と `select` コールバック(の引数)が必ず同じ型であることを保証するために、 `script` タグに `generics` 属性を追加します。 ```svelte {#each items as item} select(item)}> {item.text} {/each} ``` この `generics` 属性の書き方は、 TypeScript でジェネリック関数を定義するときの `<...>` (山括弧)内の構文とまったく同じです。言い換えると、複数のジェネリクス、 `extends` による型制約、デフォルトの型(フォールバック型)といった機能をそのまま利用できます。 ## ネイティブHTML要素をラップするコンポーネントの型付け コンポーネントを作るとき、ラップしたネイティブHTML要素( `button` など)の標準属性( `class` や `disabled` など)を、コンポーネントを使う側で自由に指定したい場合があるでしょう。そのときは `svelte/elements` が提供する型定義(インターフェース)を使用(または継承)してください。以下は `Button` コンポーネントの例です: ```svelte {@render children?.()} ``` すべての要素に専用の型定義が用意されているわけではありません。そのような要素には、 `SvelteHTMLElements` を使います: ```svelte {@render children?.()} ``` ## `$state` の型付け `$state` はほかの変数と同じように型付けできます。 ```ts let count: number = $state(0); ``` もし `$state` に初期値を設定しない場合、その型は `undefined` とのユニオン型になります。 ```ts // @noErrors // エラー: 型 'number | undefined' を型 'number' に割り当てることはできません let count: number = $state(); ``` 変数の宣言時には値が決まっていなくても、後続の処理で _必ず_ 値がセットされる、とあなたが保証できるケースがあります。そのような場合は `as` キャストを使ってください。これはプロパティの初期化が `constructor` で行われるクラスで特に便利です: ```ts class Counter { count = $state() as number; constructor(initial: number) { this.count = initial; } } ``` ## コンポーネント自体の型 Svelte コンポーネントは `Component` 型です。 `Component` 型と関連する型を使って、さまざまな制約を表現できます。 例えば動的コンポーネントと組み合わせ、渡せるコンポーネントの種類を制限します: ```svelte ``` > [!LEGACY] Svelte 4 では、コンポーネントは `SvelteComponent` 型でした。 コンポーネントからプロパティを抽出するには、 `ComponentProps` を使います。 ```ts import type { Component, ComponentProps } from 'svelte'; import MyComponent from './MyComponent.svelte'; function withProps>( component: TComponent, props: ComponentProps ) {} // 第二引数が、第一引数のコンポーネントが期待するプロパティではないとき、 // エラーが発生します。 withProps(MyComponent, { foo: 'bar' }); ``` コンポーネントのコンストラクタまたはインスタンス型を期待する変数を宣言するには: ```svelte ``` ## 組み込みDOM型の強化 Svelteは、存在するすべてのHTML DOMの型をできる限り提供しています。しかし、場合によっては、実験的な属性やアクション (action) 由来のカスタムイベントを使いたいことがあるかもしれません。そのようなケースでは、 TypeScript はそれらの型を認識できないため、型エラーを発生させます。もしそれが(実験的でない)標準の属性やイベントである場合、 Svelte が提供する [HTMLの型定義](https://github.com/sveltejs/svelte/blob/main/packages/svelte/elements.d.ts) にその型が定義されていない可能性があります。そのときは、ぜひ issue を立てたり、修正のためのプルリクエストを送ってください。 もしこれがカスタムや実験的な属性・イベントであるときは、以下のように `svelte/elements` モジュールを拡張することで、型定義を強化できます: ```ts /// file: additional-svelte-typings.d.ts import { HTMLButtonAttributes } from 'svelte/elements'; declare module 'svelte/elements' { // Svelteが認識するHTML要素のリストに、新しい要素(ここでは'custom-button')を追加します export interface SvelteHTMLElements { 'custom-button': HTMLButtonAttributes; } // すべてのHTML要素で利用可能な新しいグローバル属性を追加します export interface HTMLAttributes { globalattribute?: string; } // 特定の要素(ここでは要素)に新しい属性を追加します export interface HTMLButtonAttributes { veryexperimentalattribute?: string; } } export {}; // これがアンビエントモジュールでないことを保証します。そうしないと、型が拡張(augmented)されるのではなく、上書き(overridden)されてしまいます。 ``` 次に、その `d.ts` ファイルが `tsconfig.json` で参照されていることを確認してください。もし `"include": ["src/**/*"]` のような記述があり、 `d.ts` ファイルが `src` 内にあるなら、強化した型定義は機能するはずです。変更を有効にするには、リロードが必要かもしれません。 # Custom elements 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 `` [element](svelte-options). Within the custom element you can access the host element via the [`$host`](https://svelte.dev/docs/svelte/$host) rune. ```svelte Hello {name}! ``` You can leave out the tag name for any of your inner components which you don't want to expose and use them like regular Svelte components. Consumers of the component can still name it afterwards if needed, using the static `element` property which contains the custom element constructor and which is available when the `customElement` compiler option is `true`. ```js // @noErrors import MyElement from './MyElement.svelte'; customElements.define('my-element', MyElement.element); ``` Once a custom element has been defined, it can be used as a regular DOM element: ```js document.body.innerHTML = ` This is some slotted content `; ``` Any [props](basic-markup#Component-props) are exposed as properties of the DOM element (as well as being readable/writable as attributes, where possible). ```js // @noErrors const el = document.querySelector('my-element'); // get the current value of the 'name' prop console.log(el.name); // set a new value, updating the shadow DOM el.name = 'everybody'; ``` Note that you need to list out all properties explicitly, i.e. doing `let props = $props()` without declaring `props` in the [component options](#Component-options) means that Svelte can't know which props to expose as properties on the DOM element. ## Component lifecycle Custom elements are created from Svelte components using a wrapper approach. This means the inner Svelte component has no knowledge that it is a custom element. The custom element wrapper takes care of handling its lifecycle appropriately. When a custom element is created, the Svelte component it wraps is _not_ created right away. It is only created in the next tick after the `connectedCallback` is invoked. Properties assigned to the custom element before it is inserted into the DOM are temporarily saved and then set on component creation, so their values are not lost. The same does not work for invoking exported functions on the custom element though, they are only available after the element has mounted. If you need to invoke functions before component creation, you can work around it by using the [`extend` option](#Component-options). When a custom element written with Svelte is created or updated, the shadow DOM will reflect the value in the next tick, not immediately. This way updates can be batched, and DOM moves which temporarily (but synchronously) detach the element from the DOM don't lead to unmounting the inner component. The inner Svelte component is destroyed in the next tick after the `disconnectedCallback` is invoked. ## Component options When constructing a custom element, you can tailor several aspects by defining `customElement` as an object within `` since Svelte 4. This object may contain the following properties: - `tag: string`: an optional `tag` property for the custom element's name. If set, a custom element with this tag name will be defined with the document's `customElements` registry upon importing this component. - `shadow`: an optional property to modify shadow root properties. It accepts the following values: - `"none"`: No shadow root is created. Note that styles are then no longer encapsulated, and you can't use slots. - `"open"`: Shadow root is created with the `mode: "open"` option. - [`ShadowRootInit`](https://developer.mozilla.org/en-US/docs/Web/API/Element/attachShadow#options): You can pass a settings object that will be passed to `attachShadow()` when shadow root is created. - `props`: an optional property to modify certain details and behaviors of your component's properties. It offers the following settings: - `attribute: string`: To update a custom element's prop, you have two alternatives: either set the property on the custom element's reference as illustrated above or use an HTML attribute. For the latter, the default attribute name is the lowercase property name. Modify this by assigning `attribute: ""`. - `reflect: boolean`: By default, updated prop values do not reflect back to the DOM. To enable this behavior, set `reflect: true`. - `type: 'String' | 'Boolean' | 'Number' | 'Array' | 'Object'`: While converting an attribute value to a prop value and reflecting it back, the prop value is assumed to be a `String` by default. This may not always be accurate. For instance, for a number type, define it using `type: "Number"` You don't need to list all properties, those not listed will use the default settings. - `extend`: an optional property which expects a function as its argument. It is passed the custom element class generated by Svelte and expects you to return a custom element class. This comes in handy if you have very specific requirements to the life cycle of the custom element or want to enhance the class to for example use [ElementInternals](https://developer.mozilla.org/en-US/docs/Web/API/ElementInternals#examples) for better HTML form integration. ```svelte { // Extend the class so we can let it participate in HTML forms return class extends customElementConstructor { static formAssociated = true; constructor() { super(); this.attachedInternals = this.attachInternals(); } // Add the function here, not below in the component so that // it's always available, not just when the inner Svelte component // is mounted randomIndex() { this.elementIndex = Math.random(); } }; } }} /> ... ``` > [!NOTE] While Typescript is supported in the `extend` function, it is subject to limitations: you need to set `lang="ts"` on one of the scripts AND you can only use [erasable syntax](https://www.typescriptlang.org/tsconfig/#erasableSyntaxOnly) in it. They are not processed by script preprocessors. ## Caveats and limitations Custom elements can be a useful way to package components for consumption in a non-Svelte app, as they will work with vanilla HTML and JavaScript as well as [most frameworks](https://custom-elements-everywhere.com/). There are, however, some important differences to be aware of: - Styles are _encapsulated_, rather than merely _scoped_ (unless you set `shadow: "none"`). This means that any non-component styles (such as you might have in a `global.css` file) will not apply to the custom element, including styles with the `:global(...)` modifier - Instead of being extracted out as a separate .css file, styles are inlined into the component as a JavaScript string - Custom elements are not generally suitable for server-side rendering, as the shadow DOM is invisible until JavaScript loads - In Svelte, slotted content renders _lazily_. In the DOM, it renders _eagerly_. In other words, it will always be created even if the component's `` element is inside an `{#if ...}` block. Similarly, including a `` in an `{#each ...}` block will not cause the slotted content to be rendered multiple times - The deprecated `let:` directive has no effect, because custom elements do not have a way to pass data to the parent component that fills the slot - Polyfills are required to support older browsers - You can use Svelte's context feature between regular Svelte components within a custom element, but you can't use them across custom elements. In other words, you can't use `setContext` on a parent custom element and read that with `getContext` in a child custom element. - Don't declare properties or attributes starting with `on`, as their usage will be interpreted as an event listener. In other words, Svelte treats `` as `customElement.addEventListener('eworld', true)` (and not as `customElement.oneworld = true`) # Svelte 4 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 = (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 ------ ++++++ ``` 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`. ```svelte random ``` 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} Success {/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 count in default slot — is available: {count} count in bar slot — is not available: {count} ``` 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) # Svelte 5 migration guide Version 5 comes with an overhauled syntax and reactivity system. While it may look different at first, you'll soon notice many similarities. This guide goes over the changes in detail and shows you how to upgrade. Along with it, we also provide information on _why_ we did these changes. You don't have to migrate to the new syntax right away — Svelte 5 still supports the old Svelte 4 syntax, and you can mix and match components using the new syntax with components using the old and vice versa. We expect many people to be able to upgrade with only a few lines of code changed initially. There's also a [migration script](#Migration-script) that helps you with many of these steps automatically. ## Reactivity syntax changes At the heart of Svelte 5 is the new runes API. Runes are basically compiler instructions that inform Svelte about reactivity. Syntactically, runes are functions starting with a dollar-sign. ### let → $state In Svelte 4, a `let` declaration at the top level of a component was implicitly reactive. In Svelte 5, things are more explicit: a variable is reactive when created using the `$state` rune. Let's migrate the counter to runes mode by wrapping the counter in `$state`: ```svelte ``` Nothing else changes. `count` is still the number itself, and you read and write directly to it, without a wrapper like `.value` or `getCount()`. > [!DETAILS] Why we did this > `let` being implicitly reactive at the top level worked great, but it meant that reactivity was constrained — a `let` declaration anywhere else was not reactive. This forced you to resort to using stores when refactoring code out of the top level of components for reuse. This meant you had to learn an entirely separate reactivity model, and the result often wasn't as nice to work with. Because reactivity is more explicit in Svelte 5, you can keep using the same API outside the top level of components. Head to [the tutorial](/tutorial) to learn more. ### $: → $derived/$effect In Svelte 4, a `$:` statement at the top level of a component could be used to declare a derivation, i.e. state that is entirely defined through a computation of other state. In Svelte 5, this is achieved using the `$derived` rune: ```svelte ``` As with `$state`, nothing else changes. `double` is still the number itself, and you read it directly, without a wrapper like `.value` or `getDouble()`. A `$:` statement could also be used to create side effects. In Svelte 5, this is achieved using the `$effect` rune: ```svelte ``` Note that [when `$effect` runs is different]($effect#Understanding-dependencies) than when `$:` runs. > [!DETAILS] Why we did this > `$:` was a great shorthand and easy to get started with: you could slap a `$:` in front of most code and it would somehow work. This intuitiveness was also its drawback the more complicated your code became, because it wasn't as easy to reason about. Was the intent of the code to create a derivation, or a side effect? With `$derived` and `$effect`, you have a bit more up-front decision making to do (spoiler alert: 90% of the time you want `$derived`), but future-you and other developers on your team will have an easier time. > > There were also gotchas that were hard to spot: > > - `$:` only updated directly before rendering, which meant you could read stale values in-between rerenders > - `$:` only ran once per tick, which meant that statements may run less often than you think > - `$:` dependencies were determined through static analysis of the dependencies. This worked in most cases, but could break in subtle ways during a refactoring where dependencies would be for example moved into a function and no longer be visible as a result > - `$:` statements were also ordered by using static analysis of the dependencies. In some cases there could be ties and the ordering would be wrong as a result, needing manual interventions. Ordering could also break while refactoring code and some dependencies no longer being visible as a result. > > Lastly, it wasn't TypeScript-friendly (our editor tooling had to jump through some hoops to make it valid for TypeScript), which was a blocker for making Svelte's reactivity model truly universal. > > `$derived` and `$effect` fix all of these by > > - always returning the latest value > - running as often as needed to be stable > - determining the dependencies at runtime, and therefore being immune to refactorings > - executing dependencies as needed and therefore being immune to ordering problems > - being TypeScript-friendly ### export let → $props In Svelte 4, properties of a component were declared using `export let`. Each property was one declaration. In Svelte 5, all properties are declared through the `$props` rune, through destructuring: ```svelte ``` There are multiple cases where declaring properties becomes less straightforward than having a few `export let` declarations: - you want to rename the property, for example because the name is a reserved identifier (e.g. `class`) - you don't know which other properties to expect in advance - you want to forward every property to another component All these cases need special syntax in Svelte 4: - renaming: `export { klass as class}` - other properties: `$$restProps` - all properties `$$props` In Svelte 5, the `$props` rune makes this straightforward without any additional Svelte-specific syntax: - renaming: use property renaming `let { class: klass } = $props();` - other properties: use spreading `let { foo, bar, ...rest } = $props();` - all properties: don't destructure `let props = $props();` ```svelte click me ``` > [!DETAILS] Why we did this > `export let` was one of the more controversial API decisions, and there was a lot of debate about whether you should think about a property being `export`ed or `import`ed. `$props` doesn't have this trait. It's also in line with the other runes, and the general thinking reduces to "everything special to reactivity in Svelte is a rune". > > There were also a lot of limitations around `export let`, which required additional API, as shown above. `$props` unite this in one syntactical concept that leans heavily on regular JavaScript destructuring syntax. ## Event changes Event handlers have been given a facelift in Svelte 5. Whereas in Svelte 4 we use the `on:` directive to attach an event listener to an element, in Svelte 5 they are properties like any other (in other words — remove the colon): ```svelte count++}> clicks: {count} ``` Since they're just properties, you can use the normal shorthand syntax... ```svelte clicks: {count} ``` ...though when using a named event handler function it's usually better to use a more descriptive name. ### Component events In Svelte 4, components could emit events by creating a dispatcher with `createEventDispatcher`. This function is deprecated in Svelte 5. Instead, components should accept _callback props_ — which means you then pass functions as properties to these components: ```svelte { size += power---.detail---; if (size > 75) burst = true; }} ---on:---deflate={(power) => { if (size > 0) size -= power---.detail---; }} /> {#if burst} new balloon 💥 {:else} 🎈 {/if} ``` ```svelte ---dispatch('inflate', power)---+++inflate(power)+++}> inflate ---dispatch('deflate', power)---+++deflate(power)+++}> deflate power--}>- Pump power: {power} power++}>+ ``` ### Bubbling events Instead of doing `` to 'forward' the event from the element to the component, the component should accept an `onclick` callback prop: ```svelte click me ``` Note that this also means you can 'spread' event handlers onto the element along with other props instead of tediously forwarding each event separately: ```svelte click me ``` ### Event modifiers In Svelte 4, you can add event modifiers to handlers: ```svelte ... ``` Modifiers are specific to `on:` and so do not work with modern event handlers. Adding things like `event.preventDefault()` inside the handler itself is preferable, since all the logic lives in one place rather than being split between handler and modifiers. Since event handlers are just functions, you can create your own wrappers as necessary: ```svelte ... ``` There are three modifiers — `capture`, `passive` and `nonpassive` — that can't be expressed as wrapper functions, since they need to be applied when the event handler is bound rather than when it runs. For `capture`, we add the modifier to the event name: ```svelte ... ``` Changing the [`passive`](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#using_passive_listeners) option of an event handler, meanwhile, is not something to be done lightly. If you have a use case for it — and you probably don't! — then you will need to use an action to apply the event handler yourself. ### Multiple event handlers In Svelte 4, this is possible: ```svelte ... ``` Duplicate attributes/properties on elements — which now includes event handlers — are not allowed. Instead, do this: ```svelte { one(e); two(e); }} > ... ``` When spreading props, local event handlers must go _after_ the spread, or they risk being overwritten: ```svelte { doStuff(e); props.onclick?.(e); }} > ... ``` > [!DETAILS] Why we did this > `createEventDispatcher` was always a bit boilerplate-y: > > - import the function > - call the function to get a dispatch function > - call said dispatch function with a string and possibly a payload > - retrieve said payload on the other end through a `.detail` property, because the event itself was always a `CustomEvent` > > It was always possible to use component callback props, but because you had to listen to DOM events using `on:`, it made sense to use `createEventDispatcher` for component events due to syntactical consistency. Now that we have event attributes (`onclick`), it's the other way around: Callback props are now the more sensible thing to do. > > The removal of event modifiers is arguably one of the changes that seems like a step back for those who've liked the shorthand syntax of event modifiers. Given that they are not used that frequently, we traded a smaller surface area for more explicitness. Modifiers also were inconsistent, because most of them were only usable on DOM elements. > > Multiple listeners for the same event are also no longer possible, but it was something of an anti-pattern anyway, since it impedes readability: if there are many attributes, it becomes harder to spot that there are two handlers unless they are right next to each other. It also implies that the two handlers are independent, when in fact something like `event.stopImmediatePropagation()` inside `one` would prevent `two` from being called. > > By deprecating `createEventDispatcher` and the `on:` directive in favour of callback props and normal element properties, we: > > - reduce Svelte's learning curve > - remove boilerplate, particularly around `createEventDispatcher` > - remove the overhead of creating `CustomEvent` objects for events that may not even have listeners > - add the ability to spread event handlers > - add the ability to know which event handlers were provided to a component > - add the ability to express whether a given event handler is required or optional > - increase type safety (previously, it was effectively impossible for Svelte to guarantee that a component didn't emit a particular event) ## Snippets instead of slots In Svelte 4, content can be passed to components using slots. Svelte 5 replaces them with snippets, which are more powerful and flexible, and so slots are deprecated in Svelte 5. They continue to work, however, and you can pass snippets to a component that uses slots: ```svelte ``` ```svelte default child content {#snippet foo({ message })} message from child: {message} {/snippet} ``` (The reverse is not true — you cannot pass slotted content to a component that uses [`{@render ...}`](/docs/svelte/@render) tags.) When using custom elements, you should still use `` like before. In a future version, when Svelte removes its internal version of slots, it will leave those slots as-is, i.e. output a regular DOM tag instead of transforming it. ### Default content In Svelte 4, the easiest way to pass a piece of UI to the child was using a ``. In Svelte 5, this is done using the `children` prop instead, which is then shown with `{@render children()}`: ```svelte ------ +++{@render children?.()}+++ ``` ### Multiple content placeholders If you wanted multiple UI placeholders, you had to use named slots. In Svelte 5, use props instead, name them however you like and `{@render ...}` them: ```svelte ------ +++{@render header()}+++ ------ +++{@render main()}+++ ``` ### Passing data back up In Svelte 4, you would pass data to a `` and then retrieve it with `let:` in the parent component. In Svelte 5, snippets take on that responsibility: ```svelte +++{#snippet item(text)}+++ {text} +++{/snippet}+++ ---No items yet--- +++{#snippet empty()} No items yet {/snippet}+++ ``` ```svelte {#if items.length} {#each items as entry} ------ +++{@render item(entry)}+++ {/each} {:else} ------ +++{@render empty?.()}+++ {/if} ``` > [!DETAILS] Why we did this > Slots were easy to get started with, but the more advanced the use case became, the more involved and confusing the syntax became: > > - the `let:` syntax was confusing to many people as it _creates_ a variable whereas all other `:` directives _receive_ a variable > - the scope of a variable declared with `let:` wasn't clear. In the example above, it may look like you can use the `item` slot prop in the `empty` slot, but that's not true > - named slots had to be applied to an element using the `slot` attribute. Sometimes you didn't want to create an element, so we had to add the `` API > - named slots could also be applied to a component, which changed the semantics of where `let:` directives are available (even today us maintainers often don't know which way around it works) > > Snippets solve all of these problems by being much more readable and clear. At the same time they're more powerful as they allow you to define sections of UI that you can render _anywhere_, not just passing them as props to a component. ## Migration script By now you should have a pretty good understanding of the before/after and how the old syntax relates to the new syntax. It probably also became clear that a lot of these migrations are rather technical and repetitive — something you don't want to do by hand. We thought the same, which is why we provide a migration script to do most of the migration automatically. You can upgrade your project by using `npx sv migrate svelte-5`. This will do the following things: - bump core dependencies in your `package.json` - migrate to runes (`let` → `$state` etc) - migrate to event attributes for DOM elements (`on:click` → `onclick`) - migrate slot creations to render tags (`` → `{@render children()}`) - migrate slot usages to snippets (`...` → `{#snippet x()}...{/snippet}`) - migrate obvious component creations (`new Component(...)` → `mount(Component, ...)`) You can also migrate a single component in VS Code through the `Migrate Component to Svelte 5 Syntax` command, or in our Playground through the `Migrate` button. Not everything can be migrated automatically, and some migrations need manual cleanup afterwards. The following sections describe these in more detail. ### run You may see that the migration script converts some of your `$:` statements to a `run` function which is imported from `svelte/legacy`. This happens if the migration script couldn't reliably migrate the statement to a `$derived` and concluded this is a side effect instead. In some cases this may be wrong and it's best to change this to use a `$derived` instead. In other cases it may be right, but since `$:` statements also ran on the server but `$effect` does not, it isn't safe to transform it as such. Instead, `run` is used as a stopgap solution. `run` mimics most of the characteristics of `$:`, in that it runs on the server once, and runs as `$effect.pre` on the client (`$effect.pre` runs _before_ changes are applied to the DOM; most likely you want to use `$effect` instead). ```svelte ``` ### Event modifiers Event modifiers are not applicable to event attributes (e.g. you can't do `onclick|preventDefault={...}`). Therefore, when migrating event directives to event attributes, we need a function-replacement for these modifiers. These are imported from `svelte/legacy`, and should be migrated away from in favor of e.g. just using `event.preventDefault()`. ```svelte { +++event.preventDefault();+++ // ... })} > click me ``` ### Things that are not automigrated The migration script does not convert `createEventDispatcher`. You need to adjust those parts manually. It doesn't do it because it's too risky because it could result in breakage for users of the component, which the migration script cannot find out. The migration script does not convert `beforeUpdate/afterUpdate`. It doesn't do it because it's impossible to determine the actual intent of the code. As a rule of thumb you can often go with a combination of `$effect.pre` (runs at the same time as `beforeUpdate` did) and `tick` (imported from `svelte`, allows you to wait until changes are applied to the DOM and then do some work). ## Components are no longer classes In Svelte 3 and 4, components are classes. In Svelte 5 they are functions and should be instantiated differently. If you need to manually instantiate components, you should use `mount` or `hydrate` (imported from `svelte`) instead. If you see this error using SvelteKit, try updating to the latest version of SvelteKit first, which adds support for Svelte 5. If you're using Svelte without SvelteKit, you'll likely have a `main.js` file (or similar) which you need to adjust: ```js +++import { mount } from 'svelte';+++ import App from './App.svelte' ---const app = new App({ target: document.getElementById("app") });--- +++const app = mount(App, { target: document.getElementById("app") });+++ export default app; ``` `mount` and `hydrate` have the exact same API. The difference is that `hydrate` will pick up the Svelte's server-rendered HTML inside its target and hydrate it. Both return an object with the exports of the component and potentially property accessors (if compiled with `accessors: true`). They do not come with the `$on`, `$set` and `$destroy` methods you may know from the class component API. These are its replacements: For `$on`, instead of listening to events, pass them via the `events` property on the options argument. ```js +++import { mount } from 'svelte';+++ import App from './App.svelte' ---const app = new App({ target: document.getElementById("app") }); app.$on('event', callback);--- +++const app = mount(App, { target: document.getElementById("app"), events: { event: callback } });+++ ``` > [!NOTE] Note that using `events` is discouraged — instead, [use callbacks](#Event-changes) For `$set`, use `$state` instead to create a reactive property object and manipulate it. If you're doing this inside a `.js` or `.ts` file, adjust the ending to include `.svelte`, i.e. `.svelte.js` or `.svelte.ts`. ```js +++import { mount } from 'svelte';+++ import App from './App.svelte' ---const app = new App({ target: document.getElementById("app"), props: { foo: 'bar' } }); app.$set({ foo: 'baz' });--- +++const props = $state({ foo: 'bar' }); const app = mount(App, { target: document.getElementById("app"), props }); props.foo = 'baz';+++ ``` For `$destroy`, use `unmount` instead. ```js +++import { mount, unmount } from 'svelte';+++ import App from './App.svelte' ---const app = new App({ target: document.getElementById("app"), props: { foo: 'bar' } }); app.$destroy();--- +++const app = mount(App, { target: document.getElementById("app") }); unmount(app);+++ ``` As a stop-gap-solution, you can also use `createClassComponent` or `asClassComponent` (imported from `svelte/legacy`) instead to keep the same API known from Svelte 4 after instantiating. ```js +++import { createClassComponent } from 'svelte/legacy';+++ import App from './App.svelte' ---const app = new App({ target: document.getElementById("app") });--- +++const app = createClassComponent({ component: App, target: document.getElementById("app") });+++ export default app; ``` If this component is not under your control, you can use the `compatibility.componentApi` compiler option for auto-applied backwards compatibility, which means code using `new Component(...)` keeps working without adjustments (note that this adds a bit of overhead to each component). This will also add `$set` and `$on` methods for all component instances you get through `bind:this`. ```js /// svelte.config.js export default { compilerOptions: { compatibility: { componentApi: 4 } } }; ``` Note that `mount` and `hydrate` are _not_ synchronous, so things like `onMount` won't have been called by the time the function returns and the pending block of promises will not have been rendered yet (because `#await` waits a microtask to wait for a potentially immediately-resolved promise). If you need that guarantee, call `flushSync` (import from `'svelte'`) after calling `mount/hydrate`. ### Server API changes Similarly, components no longer have a `render` method when compiled for server-side rendering. Instead, pass the function to `render` from `svelte/server`: ```js +++import { render } from 'svelte/server';+++ import App from './App.svelte'; ---const { html, head } = App.render({ props: { message: 'hello' }});--- +++const { html, head } = render(App, { props: { message: 'hello' }});+++ ``` In Svelte 4, rendering a component to a string also returned the CSS of all components. In Svelte 5, this is no longer the case by default because most of the time you're using a tooling chain that takes care of it in other ways (like SvelteKit). If you need CSS to be returned from `render`, you can set the `css` compiler option to `'injected'` and it will add ` ``` ### custom_element_props_identifier ``` Using a rest element or a non-destructured declaration with `$props()` means that Svelte can't infer what properties to expose when creating a custom element. Consider destructuring all the props or explicitly specifying the `customElement.props` option. ``` ### element_implicitly_closed ``` This element is implicitly closed by the following `%tag%`, which can cause an unexpected DOM structure. Add an explicit `%closing%` to avoid surprises. ``` In HTML, some elements are implicitly closed by another element. For example, you cannot nest a `` inside another ``: ```html hello hello ``` Similarly, a parent element's closing tag will implicitly close all child elements, even if the `` was a typo and you meant to create a _new_ element. To avoid ambiguity, it's always a good idea to have an explicit closing tag. ### element_invalid_self_closing_tag ``` Self-closing HTML tags for non-void elements are ambiguous — use `<%name% ...>%name%>` rather than `<%name% ... />` ``` In HTML, there's [no such thing as a self-closing tag](https://jakearchibald.com/2023/against-self-closing-tags-in-html/). While this _looks_ like a self-contained element with some text next to it... ```html some text! ``` ...a spec-compliant HTML parser (such as a browser) will in fact parse it like this, with the text _inside_ the icon: ```html some text! ``` Some templating languages (including Svelte) will 'fix' HTML by turning `` into ``. Others adhere to the spec. Both result in ambiguity and confusion when copy-pasting code between different contexts, so Svelte prompts you to resolve the ambiguity directly by having an explicit closing tag. To automate this, run the dedicated migration: ```sh npx sv migrate self-closing-tags ``` In a future version of Svelte, self-closing tags may be upgraded from a warning to an error. ### event_directive_deprecated ``` Using `on:%name%` to listen to the %name% event is deprecated. Use the event attribute `on%name%` instead ``` See [the migration guide](v5-migration-guide#Event-changes) for more info. ### export_let_unused ``` Component has unused export property '%name%'. If it is for external reference only, please consider using `export const %name%` ``` ### legacy_code ``` `%code%` is no longer valid — please use `%suggestion%` instead ``` ### legacy_component_creation ``` Svelte 5 components are no longer classes. Instantiate them using `mount` or `hydrate` (imported from 'svelte') instead. ``` See the [migration guide](v5-migration-guide#Components-are-no-longer-classes) for more info. ### node_invalid_placement_ssr ``` %message%. When rendering this component on the server, the resulting HTML will be modified by the browser (by moving, removing, or inserting elements), likely resulting in a `hydration_mismatch` warning ``` HTML restricts where certain elements can appear. In case of a violation the browser will 'repair' the HTML in a way that breaks Svelte's assumptions about the structure of your components. Some examples: - `hello world` will result in `hello world` (the `` autoclosed the `` because `` cannot contain block-level elements) - `option a` will result in `option a` (the `` is removed) - `cell` will result in `cell` (a `` is auto-inserted) This code will work when the component is rendered on the client (which is why this is a warning rather than an error), but if you use server rendering it will cause hydration to fail. ### non_reactive_update ``` `%name%` is updated, but is not declared with `$state(...)`. Changing its value will not correctly trigger updates ``` This warning is thrown when the compiler detects the following: - a variable was declared without `$state` or `$state.raw` - the variable is reassigned - the variable is read in a reactive context In this case, changing the value will not correctly trigger updates. Example: ```svelte This value updates: {reactive} This value does not update: {stale} { stale = 'updated'; reactive = 'updated'; }}>update ``` To fix this, wrap your variable declaration with `$state`. ### options_deprecated_accessors ``` The `accessors` option has been deprecated. It will have no effect in runes mode ``` ### options_deprecated_immutable ``` The `immutable` option has been deprecated. It will have no effect in runes mode ``` ### options_missing_custom_element ``` The `customElement` option is used when generating a custom element. Did you forget the `customElement: true` compile option? ``` ### options_removed_enable_sourcemap ``` The `enableSourcemap` option has been removed. Source maps are always generated now, and tooling can choose to ignore them ``` ### options_removed_hydratable ``` The `hydratable` option has been removed. Svelte components are always hydratable now ``` ### options_removed_loop_guard_timeout ``` The `loopGuardTimeout` option has been removed ``` ### options_renamed_ssr_dom ``` `generate: "dom"` and `generate: "ssr"` options have been renamed to "client" and "server" respectively ``` ### perf_avoid_inline_class ``` Avoid 'new class' — instead, declare the class at the top level scope ``` ### perf_avoid_nested_class ``` Avoid declaring classes below the top level scope ``` ### reactive_declaration_invalid_placement ``` Reactive declarations only exist at the top level of the instance script ``` ### reactive_declaration_module_script_dependency ``` Reassignments of module-level declarations will not cause reactive statements to update ``` ### script_context_deprecated ``` `context="module"` is deprecated, use the `module` attribute instead ``` ```svelte ``` ### script_unknown_attribute ``` Unrecognized attribute — should be one of `generics`, `lang` or `module`. If this exists for a preprocessor, ensure that the preprocessor removes it ``` ### slot_element_deprecated ``` Using `` to render parent content is deprecated. Use `{@render ...}` tags instead ``` See [the migration guide](v5-migration-guide#Snippets-instead-of-slots) for more info. ### state_referenced_locally ``` This reference only captures the initial value of `%name%`. Did you mean to reference it inside a %type% instead? ``` This warning is thrown when the compiler detects the following: - A reactive variable is declared - ...and later reassigned... - ...and referenced in the same scope This 'breaks the link' to the original state declaration. For example, if you pass the state to a function, the function loses access to the state once it is reassigned: ```svelte count++}> increment ``` ```svelte The count is {count} ``` To fix this, reference the variable such that it is lazily evaluated. For the above example, this can be achieved by wrapping `count` in a function: ```svelte count++}> increment ``` ```svelte The count is {+++count()+++} ``` For more info, see [Passing state into functions]($state#Passing-state-into-functions). ### store_rune_conflict ``` It looks like you're using the `$%name%` rune, but there is a local binding called `%name%`. Referencing a local variable with a `$` prefix will create a store subscription. Please rename `%name%` to avoid the ambiguity ``` ### svelte_component_deprecated ``` `` is deprecated in runes mode — components are dynamic by default ``` In previous versions of Svelte, the component constructor was fixed when the component was rendered. In other words, if you wanted `` to re-render when `X` changed, you would either have to use `` or put the component inside a `{#key X}...{/key}` block. In Svelte 5 this is no longer true — if `X` changes, `` re-renders. In some cases `` syntax can be used as a replacement; a lowercased variable with property access is recognized as a component in Svelte 5. For complex component resolution logic, an intermediary, capitalized variable may be necessary. E.g. in places where `@const` can be used: ```svelte {#each items as item} ------ +++{@const Component = item.condition ? Y : Z}+++ ++++++ {/each} ``` A derived value may be used in other contexts: ```svelte ------ ++++++ ``` ### svelte_element_invalid_this ``` `this` should be an `{expression}`. Using a string attribute value will cause an error in future versions of Svelte ``` ### svelte_self_deprecated ``` `` is deprecated — use self-imports (e.g. `import %name% from './%basename%'`) instead ``` See [the note in the docs](legacy-svelte-self) for more info. ### unknown_code ``` `%code%` is not a recognised code ``` ``` `%code%` is not a recognised code (did you mean `%suggestion%`?) ``` # Runtime errors ## Client errors ### async_derived_orphan ``` Cannot create a `$derived(...)` with an `await` expression outside of an effect tree ``` In Svelte there are two types of reaction — [`$derived`](/docs/svelte/$derived) and [`$effect`](/docs/svelte/$effect). Deriveds can be created anywhere, because they run _lazily_ and can be [garbage collected](https://developer.mozilla.org/en-US/docs/Glossary/Garbage_collection) if nothing references them. Effects, by contrast, keep running eagerly whenever their dependencies change, until they are destroyed. Because of this, effects can only be created inside other effects (or [effect roots](/docs/svelte/$effect#$effect.root), such as the one that is created when you first mount a component) so that Svelte knows when to destroy them. Some sleight of hand occurs when a derived contains an `await` expression: Since waiting until we read `{await getPromise()}` to call `getPromise` would be too late, we use an effect to instead call it proactively, notifying Svelte when the value is available. But since we're using an effect, we can only create asynchronous deriveds inside another effect. ### bind_invalid_checkbox_value ``` Using `bind:value` together with a checkbox input is not allowed. Use `bind:checked` instead ``` ### bind_invalid_export ``` Component %component% has an export named `%key%` that a consumer component is trying to access using `bind:%key%`, which is disallowed. Instead, use `bind:this` (e.g. `<%name% bind:this={component} />`) and then access the property on the bound component instance (e.g. `component.%key%`) ``` ### bind_not_bindable ``` A component is attempting to bind to a non-bindable property `%key%` belonging to %component% (i.e. `<%name% bind:%key%={...}>`). To mark a property as bindable: `let { %key% = $bindable() } = $props()` ``` ### component_api_changed ``` Calling `%method%` on a component instance (of %component%) is no longer valid in Svelte 5 ``` See the [migration guide](/docs/svelte/v5-migration-guide#Components-are-no-longer-classes) for more information. ### component_api_invalid_new ``` Attempted to instantiate %component% with `new %name%`, which is no longer valid in Svelte 5. If this component is not under your control, set the `compatibility.componentApi` compiler option to `4` to keep it working. ``` See the [migration guide](/docs/svelte/v5-migration-guide#Components-are-no-longer-classes) for more information. ### derived_references_self ``` A derived value cannot reference itself recursively ``` ### each_key_duplicate ``` Keyed each block has duplicate key at indexes %a% and %b% ``` ``` Keyed each block has duplicate key `%value%` at indexes %a% and %b% ``` ### each_key_volatile ``` Keyed each block has key that is not idempotent — the key for item at index %index% was `%a%` but is now `%b%`. Keys must be the same each time for a given item ``` The key expression in a keyed each block must return the same value when called multiple times for the same item. Using expressions like `[item.a, item.b]` creates a new array each time, which will never be equal to itself. Instead, use a primitive value or create a stable key like `item.a + '-' + item.b`. ### effect_in_teardown ``` `%rune%` cannot be used inside an effect cleanup function ``` ### effect_in_unowned_derived ``` Effect cannot be created inside a `$derived` value that was not itself created inside an effect ``` ### effect_orphan ``` `%rune%` can only be used inside an effect (e.g. during component initialisation) ``` ### effect_pending_outside_reaction ``` `$effect.pending()` can only be called inside an effect or derived ``` ### effect_update_depth_exceeded ``` Maximum update depth exceeded. This typically indicates that an effect reads and writes the same piece of state ``` If an effect updates some state that it also depends on, it will re-run, potentially in a loop: ```js let count = $state(0); $effect(() => { // this both reads and writes `count`, // so will run in an infinite loop count += 1; }); ``` (Svelte intervenes before this can crash your browser tab.) The same applies to array mutations, since these both read and write to the array: ```js let array = $state(['hello']); $effect(() => { array.push('goodbye'); }); ``` Note that it's fine for an effect to re-run itself as long as it 'settles': ```js let array = ['a', 'b', 'c']; // ---cut--- $effect(() => { // this is okay, because sorting an already-sorted array // won't result in a mutation array.sort(); }); ``` Often when encountering this issue, the value in question shouldn't be state (for example, if you are pushing to a `logs` array in an effect, make `logs` a normal array rather than `$state([])`). In the rare cases where you really _do_ need to write to state in an effect — [which you should avoid]($effect#When-not-to-use-$effect) — you can read the state with [untrack](svelte#untrack) to avoid adding it as a dependency. ### flush_sync_in_effect ``` Cannot use `flushSync` inside an effect ``` The `flushSync()` function can be used to flush any pending effects synchronously. It cannot be used if effects are currently being flushed — in other words, you can call it after a state change but _not_ inside an effect. This restriction only applies when using the `experimental.async` option, which will be active by default in Svelte 6. ### fork_discarded ``` Cannot commit a fork that was already discarded ``` ### fork_timing ``` Cannot create a fork inside an effect or when state changes are pending ``` ### get_abort_signal_outside_reaction ``` `getAbortSignal()` can only be called inside an effect or derived ``` ### hydratable_missing_but_required ``` Expected to find a hydratable with key `%key%` during hydration, but did not. ``` This can happen if you render a hydratable on the client that was not rendered on the server, and means that it was forced to fall back to running its function blockingly during hydration. This is bad for performance, as it blocks hydration until the asynchronous work completes. ```svelte ``` ### hydration_failed ``` Failed to hydrate the application ``` ### invalid_snippet ``` Could not `{@render}` snippet due to the expression being `null` or `undefined`. Consider using optional chaining `{@render snippet?.()}` ``` ### lifecycle_legacy_only ``` `%name%(...)` cannot be used in runes mode ``` ### props_invalid_value ``` Cannot do `bind:%key%={undefined}` when `%key%` has a fallback value ``` ### props_rest_readonly ``` Rest element properties of `$props()` such as `%property%` are readonly ``` ### rune_outside_svelte ``` The `%rune%` rune is only available inside `.svelte` and `.svelte.js/ts` files ``` ### set_context_after_init ``` `setContext` must be called when a component first initializes, not in a subsequent effect or after an `await` expression ``` This restriction only applies when using the `experimental.async` option, which will be active by default in Svelte 6. ### state_descriptors_fixed ``` Property descriptors defined on `$state` objects must contain `value` and always be `enumerable`, `configurable` and `writable`. ``` ### state_prototype_fixed ``` Cannot set prototype of `$state` object ``` ### state_unsafe_mutation ``` Updating state inside `$derived(...)`, `$inspect(...)` or a template expression is forbidden. If the value should not be reactive, declare it without `$state` ``` This error occurs when state is updated while evaluating a `$derived`. You might encounter it while trying to 'derive' two pieces of state in one go: ```svelte count++}>{count} {count} is even: {even} {count} is odd: {odd} ``` This is forbidden because it introduces instability: if `{count} is even: {even}` is updated before `odd` is recalculated, `even` will be stale. In most cases the solution is to make everything derived: ```js let count = 0; // ---cut--- let even = $derived(count % 2 === 0); let odd = $derived(!even); ``` If side-effects are unavoidable, use [`$effect`]($effect) instead. ### svelte_boundary_reset_onerror ``` A `` `reset` function cannot be called while an error is still being handled ``` If a [``](https://svelte.dev/docs/svelte/svelte-boundary) has an `onerror` function, it must not call the provided `reset` function synchronously since the boundary is still in a broken state. Typically, `reset()` is called later, once the error has been resolved. If it's possible to resolve the error inside the `onerror` callback, you must at least wait for the boundary to settle before calling `reset()`, for example using [`tick`](https://svelte.dev/docs/svelte/lifecycle-hooks#tick): ```svelte { fixTheError(); +++await tick();+++ reset(); }}> ``` ## Server errors ### async_local_storage_unavailable ``` The node API `AsyncLocalStorage` is not available, but is required to use async server rendering. ``` Some platforms require configuration flags to enable this API. Consult your platform's documentation. ### await_invalid ``` Encountered asynchronous work while rendering synchronously. ``` You (or the framework you're using) called [`render(...)`](svelte-server#render) with a component containing an `await` expression. Either `await` the result of `render` or wrap the `await` (or the component containing it) in a [``](svelte-boundary) with a `pending` snippet. ### dynamic_element_invalid_tag ``` `` is not a valid element name — the element will not be rendered ``` The value passed to the `this` prop of `` must be a valid HTML element, SVG element, MathML element, or custom element name. A value containing invalid characters (such as whitespace or special characters) was provided, which could be a security risk. Ensure only valid tag names are passed. ### html_deprecated ``` The `html` property of server render results has been deprecated. Use `body` instead. ``` ### hydratable_clobbering ``` Attempted to set `hydratable` with key `%key%` twice with different values. %stack% ``` This error occurs when using `hydratable` multiple times with the same key. To avoid this, you can: - Ensure all invocations with the same key result in the same value - Update the keys to make both instances unique ```svelte ``` ### hydratable_serialization_failed ``` Failed to serialize `hydratable` data for key `%key%`. `hydratable` can serialize anything [`uneval` from `devalue`](https://npmjs.com/package/uneval) can, plus Promises. Cause: %stack% ``` ### invalid_csp ``` `csp.nonce` was set while `csp.hash` was `true`. These options cannot be used simultaneously. ``` ### invalid_id_prefix ``` The `idPrefix` option cannot include `--`. ``` ### lifecycle_function_unavailable ``` `%name%(...)` is not available on the server ``` Certain methods such as `mount` cannot be invoked while running in a server context. Avoid calling them eagerly, i.e. not during render. ### server_context_required ``` Could not resolve `render` context. ``` Certain functions such as `hydratable` cannot be invoked outside of a `render(...)` call, such as at the top level of a module. ## Shared errors ### experimental_async_required ``` Cannot use `%name%(...)` unless the `experimental.async` compiler option is `true` ``` ### invalid_default_snippet ``` Cannot use `{@render children(...)}` if the parent component uses `let:` directives. Consider using a named snippet instead ``` This error would be thrown in a setup like this: ```svelte {entry} ``` ```svelte {#each items as item} {@render children(item)} {/each} ``` Here, `List.svelte` is using `{@render children(item)` which means it expects `Parent.svelte` to use snippets. Instead, `Parent.svelte` uses the deprecated `let:` directive. This combination of APIs is incompatible, hence the error. ### invalid_snippet_arguments ``` A snippet function was passed invalid arguments. Snippets should only be instantiated via `{@render ...}` ``` ### invariant_violation ``` An invariant violation occurred, meaning Svelte's internal assumptions were flawed. This is a bug in Svelte, not your app — please open an issue at https://github.com/sveltejs/svelte, citing the following message: "%message%" ``` ### lifecycle_outside_component ``` `%name%(...)` can only be used during component initialisation ``` Certain lifecycle methods can only be used during component initialisation. To fix this, make sure you're invoking the method inside the _top level of the instance script_ of your component. ```svelte click me ``` ### missing_context ``` Context was not set in a parent component ``` The [`createContext()`](svelte#createContext) utility returns a `[get, set]` pair of functions. `get` will throw an error if `set` was not used to set the context in a parent component. ### snippet_without_render_tag ``` Attempted to render a snippet without a `{@render}` block. This would cause the snippet code to be stringified instead of its content being rendered to the DOM. To fix this, change `{snippet}` to `{@render snippet()}`. ``` A component throwing this error will look something like this (`children` is not being rendered): ```svelte {children} ``` ...or like this (a parent component is passing a snippet where a non-snippet value is expected): ```svelte {#snippet label()} Hi! {/snippet} ``` ```svelte {label} ``` ### store_invalid_shape ``` `%name%` is not a store with a `subscribe` method ``` ### svelte_element_invalid_this_value ``` The `this` prop on `` must be a string, if defined ``` # Runtime warnings ## Client warnings ### assignment_value_stale ``` Assignment to `%property%` property (%location%) will evaluate to the right-hand side, not the value of `%property%` following the assignment. This may result in unexpected behaviour. ``` Given a case like this... ```svelte add items: {JSON.stringify(object.items)} ``` ...the array being pushed to when the button is first clicked is the `[]` on the right-hand side of the assignment, but the resulting value of `object.array` is an empty state proxy. As a result, the pushed value will be discarded. You can fix this by separating it into two statements: ```js let object = { array: [0] }; // ---cut--- function add() { object.array ??= []; object.array.push(object.array.length); } ``` ### await_reactivity_loss ``` Detected reactivity loss when reading `%name%`. This happens when state is read in an async function after an earlier `await` ``` Svelte's signal-based reactivity works by tracking which bits of state are read when a template or `$derived(...)` expression executes. If an expression contains an `await`, Svelte transforms it such that any state _after_ the `await` is also tracked — in other words, in a case like this... ```js let a = Promise.resolve(1); let b = 2; // ---cut--- let total = $derived(await a + b); ``` ...both `a` and `b` are tracked, even though `b` is only read once `a` has resolved, after the initial execution. This does _not_ apply to an `await` that is not 'visible' inside the expression. In a case like this... ```js let a = Promise.resolve(1); let b = 2; // ---cut--- async function sum() { return await a + b; } let total = $derived(await sum()); ``` ...`total` will depend on `a` (which is read immediately) but not `b` (which is not). The solution is to pass the values into the function: ```js let a = Promise.resolve(1); let b = 2; // ---cut--- /** * @param {Promise} a * @param {number} b */ async function sum(a, b) { return await a + b; } let total = $derived(await sum(a, b)); ``` ### await_waterfall ``` An async derived, `%name%` (%location%) was not read immediately after it resolved. This often indicates an unnecessary waterfall, which can slow down your app ``` In a case like this... ```js async function one() { return 1 } async function two() { return 2 } // ---cut--- let a = $derived(await one()); let b = $derived(await two()); ``` ...the second `$derived` will not be created until the first one has resolved. Since `await two()` does not depend on the value of `a`, this delay, often described as a 'waterfall', is unnecessary. (Note that if the values of `await one()` and `await two()` subsequently change, they can do so concurrently — the waterfall only occurs when the deriveds are first created.) You can solve this by creating the promises first and _then_ awaiting them: ```js async function one() { return 1 } async function two() { return 2 } // ---cut--- let aPromise = $derived(one()); let bPromise = $derived(two()); let a = $derived(await aPromise); let b = $derived(await bPromise); ``` ### binding_property_non_reactive ``` `%binding%` is binding to a non-reactive property ``` ``` `%binding%` (%location%) is binding to a non-reactive property ``` ### console_log_state ``` Your `console.%method%` contained `$state` proxies. Consider using `$inspect(...)` or `$state.snapshot(...)` instead ``` When logging a [proxy](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy), browser devtools will log the proxy itself rather than the value it represents. In the case of Svelte, the 'target' of a `$state` proxy might not resemble its current value, which can be confusing. The easiest way to log a value as it changes over time is to use the [`$inspect`](/docs/svelte/$inspect) rune. Alternatively, to log things on a one-off basis (for example, inside an event handler) you can use [`$state.snapshot`](/docs/svelte/$state#$state.snapshot) to take a snapshot of the current value. ### derived_inert ``` Reading a derived belonging to a now-destroyed effect may result in stale values ``` A `$derived` value created inside an effect will stop updating when the effect is destroyed. You should create the `$derived` outside the effect, or inside an `$effect.root`. ### event_handler_invalid ``` %handler% should be a function. Did you mean to %suggestion%? ``` ### hydratable_missing_but_expected ``` Expected to find a hydratable with key `%key%` during hydration, but did not. ``` This can happen if you render a hydratable on the client that was not rendered on the server, and means that it was forced to fall back to running its function blockingly during hydration. This is bad for performance, as it blocks hydration until the asynchronous work completes. ```svelte ``` ### hydration_attribute_changed ``` The `%attribute%` attribute on `%html%` changed its value between server and client renders. The client value, `%value%`, will be ignored in favour of the server value ``` Certain attributes like `src` on an `` element will not be repaired during hydration, i.e. the server value will be kept. That's because updating these attributes can cause the image to be refetched (or in the case of an ``, for the frame to be reloaded), even if they resolve to the same resource. To fix this, either silence the warning with a [`svelte-ignore`](basic-markup#Comments) comment, or ensure that the value stays the same between server and client. If you really need the value to change on hydration, you can force an update like this: ```svelte ``` ### hydration_html_changed ``` The value of an `{@html ...}` block changed between server and client renders. The client value will be ignored in favour of the server value ``` ``` The value of an `{@html ...}` block %location% changed between server and client renders. The client value will be ignored in favour of the server value ``` If the `{@html ...}` value changes between the server and the client, it will not be repaired during hydration, i.e. the server value will be kept. That's because change detection during hydration is expensive and usually unnecessary. To fix this, either silence the warning with a [`svelte-ignore`](basic-markup#Comments) comment, or ensure that the value stays the same between server and client. If you really need the value to change on hydration, you can force an update like this: ```svelte {@html markup} ``` ### hydration_mismatch ``` Hydration failed because the initial UI does not match what was rendered on the server ``` ``` Hydration failed because the initial UI does not match what was rendered on the server. The error occurred near %location% ``` This warning is thrown when Svelte encounters an error while hydrating the HTML from the server. During hydration, Svelte walks the DOM, expecting a certain structure. If that structure is different (for example because the HTML was repaired by the DOM because of invalid HTML), then Svelte will run into issues, resulting in this warning. During development, this error is often preceded by a `console.error` detailing the offending HTML, which needs fixing. ### invalid_raw_snippet_render ``` The `render` function passed to `createRawSnippet` should return HTML for a single element ``` ### legacy_recursive_reactive_block ``` Detected a migrated `$:` reactive block in `%filename%` that both accesses and updates the same reactive value. This may cause recursive updates when converted to an `$effect`. ``` ### lifecycle_double_unmount ``` Tried to unmount a component that was not mounted ``` ### ownership_invalid_binding ``` %parent% passed property `%prop%` to %child% with `bind:`, but its parent component %owner% did not declare `%prop%` as a binding. Consider creating a binding between %owner% and %parent% (e.g. `bind:%prop%={...}` instead of `%prop%={...}`) ``` Consider three components `GrandParent`, `Parent` and `Child`. If you do ``, inside `GrandParent` pass on the variable via `` (note the missing `bind:`) and then do `` inside `Parent`, this warning is thrown. To fix it, `bind:` to the value instead of just passing a property (i.e. in this example do ``). ### ownership_invalid_mutation ``` Mutating unbound props (`%name%`, at %location%) is strongly discouraged. Consider using `bind:%prop%={...}` in %parent% (or using a callback) instead ``` Consider the following code: ```svelte ``` ```svelte ``` `Child` is mutating `person` which is owned by `App` without being explicitly "allowed" to do so. This is strongly discouraged since it can create code that is hard to reason about at scale ("who mutated this value?"), hence the warning. To fix it, either create callback props to communicate changes, or mark `person` as [`$bindable`]($bindable). ### select_multiple_invalid_value ``` The `value` property of a `` element should be an array, but it received a non-array value. The selection will be kept as is. ``` When using ``, Svelte will mark all selected `` elements as selected by iterating over the array passed to `value`. If `value` is not an array, Svelte will emit this warning and keep the selected options as they are. To silence the warning, ensure that `value`: - is an array for an explicit selection - is `null` or `undefined` to keep the selection as is ### state_proxy_equality_mismatch ``` Reactive `$state(...)` proxies and the values they proxy have different identities. Because of this, comparisons with `%operator%` will produce unexpected results ``` `$state(...)` creates a [proxy](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy) of the value it is passed. The proxy and the value have different identities, meaning equality checks will always return `false`: ```svelte ``` To resolve this, ensure you're comparing values where both values were created with `$state(...)`, or neither were. Note that `$state.raw(...)` will _not_ create a state proxy. ### state_proxy_unmount ``` Tried to unmount a state proxy, rather than a component ``` `unmount` was called with a state proxy: ```js import { mount, unmount } from 'svelte'; import Component from './Component.svelte'; let target = document.body; // ---cut--- let component = $state(mount(Component, { target })); // later... unmount(component); ``` Avoid using `$state` here. If `component` _does_ need to be reactive for some reason, use `$state.raw` instead. ### svelte_boundary_reset_noop ``` A `` `reset` function only resets the boundary the first time it is called ``` When an error occurs while rendering the contents of a [``](https://svelte.dev/docs/svelte/svelte-boundary), the `onerror` handler is called with the error plus a `reset` function that attempts to re-render the contents. This `reset` function should only be called once. After that, it has no effect — in a case like this, where a reference to `reset` is stored outside the boundary, clicking the button while `` is rendered will _not_ cause the contents to be rendered again. ```svelte reset (reset = r)}> {#snippet failed(e)} oops! {e.message} {/snippet} ``` ### transition_slide_display ``` The `slide` transition does not work correctly for elements with `display: %value%` ``` The [slide](/docs/svelte/svelte-transition#slide) transition works by animating the `height` of the element, which requires a `display` style like `block`, `flex` or `grid`. It does not work for: - `display: inline` (which is the default for elements like ``), and its variants like `inline-block`, `inline-flex` and `inline-grid` - `display: table` and `table-[name]`, which are the defaults for elements like `` and `` - `display: contents` ## Shared warnings ### dynamic_void_element_content ``` `` is a void element — it cannot have content ``` Elements such as `` cannot have content, any children passed to these elements will be ignored. ### state_snapshot_uncloneable ``` Value cannot be cloned with `$state.snapshot` — the original value was returned ``` ``` The following properties cannot be cloned with `$state.snapshot` — the return value contains the originals: %properties% ``` `$state.snapshot` tries to clone the given value in order to return a reference that no longer changes. Certain objects may not be cloneable, in which case the original value is returned. In the following example, `property` is cloned, but `window` is not, because DOM elements are uncloneable: ```js const object = $state({ property: 'this is cloneable', window }) const snapshot = $state.snapshot(object); ``` # Overview Svelte 5 introduced some significant changes to Svelte's API, including [runes](what-are-runes), [snippets](snippet) and event attributes. As a result, some Svelte 3/4 features are deprecated (though supported for now, unless otherwise specified) and will eventually be removed. We recommend that you incrementally [migrate your existing code](v5-migration-guide). The following pages document these features for - people still using Svelte 3/4 - people using Svelte 5, but with components that haven't yet been migrated Since Svelte 3/4 syntax still works in Svelte 5, we will distinguish between _legacy mode_ and _runes mode_. Once a component is in runes mode (which you can opt into by using runes, or by explicitly setting the `runes: true` compiler option), legacy mode features are no longer available. If you're exclusively interested in the Svelte 3/4 syntax, you can browse its documentation at [v4.svelte.dev](https://v4.svelte.dev). # Reactive let/var declarations In runes mode, reactive state is explicitly declared with the [`$state` rune]($state). In legacy mode, variables declared at the top level of a component are automatically considered _reactive_. Reassigning or mutating these variables (`count += 1` or `object.x = y`) will cause the UI to update. ```svelte count += 1}> clicks: {count} ``` 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 ``` # 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; } ``` # 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 greeter.greet('world')}> greet ``` ## 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 ``` # $$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 `` component might need to pass along all its props to its own `` element, except the `variant` prop: ```svelte click me ``` In Svelte 3/4 using `$$props` and `$$restProps` creates a modest performance penalty, so they should only be used when needed. # on: In runes mode, event handlers are just like any other attribute or prop. In legacy mode, we use the `on:` directive: ```svelte count: {count} ``` Handlers can be declared inline with no performance penalty: ```svelte (count += 1)}> count: {count} ``` 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 The component itself will emit the click event ``` It's possible to have multiple event listeners for the same event: ```svelte clicks: {count} ``` ## Component events Components can dispatch events by creating a _dispatcher_ when they are initialised: ```svelte dispatch('decrement')}>decrement dispatch('increment')}>increment ``` `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 > > > > decrement > increment > ``` # `` 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 ++++++ open = false}> close ++++++ {/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. ```svelte {#each items as data} {/each} ``` ```svelte {processed.text} ``` The usual shorthand rules apply — `let:item` is equivalent to `let:item={item}`, and `` is equivalent to ``. Named slots can also expose values. The `let:` directive goes on the element with the `slot` attribute. ```svelte {#each items as item} {/each} ``` ```svelte {item.text} Copyright (c) 2019 Svelte Industries ``` # $$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 ``` # `` The `` 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 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 # `` In runes mode, `` 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 ``, which destroys and recreates the component instance when the value of its `this` expression changes: ```svelte ``` If `this` is falsy, no component is rendered. # `` 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} > ``` # 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 `