{#snippet ...}
{#snippet name()}...{/snippet}
{#snippet name(param1, param2, paramN)}...{/snippet}
スニペット、そしてレンダータグは、コンポーネント内部で再利用可能なマークアップのチャンクを作成する方法です。このような重複したコードを書く代わりに...
{#each images as image}
{#if image.href}
<a href={image.href}>
<figure>
<img src={image.src} alt={image.caption} width={image.width} height={image.height} />
<figcaption>{image.caption}</figcaption>
</figure>
</a>
{:else}
<figure>
<img src={image.src} alt={image.caption} width={image.width} height={image.height} />
<figcaption>{image.caption}</figcaption>
</figure>
{/if}
{/each}
...このように書くことができます。
{#snippet figure(image)}
<figure>
<img src={image.src} alt={image.caption} width={image.width} height={image.height} />
<figcaption>{image.caption}</figcaption>
</figure>
{/snippet}
{#each images as image}
{#if image.href}
<a href={image.href}>
{@render figure(image)}
</a>
{:else}
{@render figure(image)}
{/if}
{/each}
関数宣言と同様に、スニペットは任意の数の引数を持つことができ、デフォルト値を設定することもできます。また、各引数を分割することもできます。ただし、レストパラメータは使用できません。
スニペットのスコープ
スニペットはコンポーネント内のどこにでも宣言できます。 <script>
タグや {#each ...}
ブロック (デモ) で宣言された値を参照できます...
<script>
let { message = `it's great to see you!` } = $props();
</script>
{#snippet hello(name)}
<p>hello {name}! {message}!</p>
{/snippet}
{@render hello('alice')}
{@render hello('bob')}
...そして、それらは同じレキシカルスコープ(つまり、兄弟とその兄弟の子)内のすべてから「見える」ようになります。
<div>
{#snippet x()}
{#snippet y()}...{/snippet}
<!-- this is fine -->
{@render y()}
{/snippet}
<!-- this will error, as `y` is not in scope -->
{@render y()}
</div>
<!-- this will also error, as `x` is not in scope -->
{@render x()}
スニペットは自身と相互を参照できます (デモ)
{#snippet blastoff()}
<span>🚀</span>
{/snippet}
{#snippet countdown(n)}
{#if n > 0}
<span>{n}...</span>
{@render countdown(n - 1)}
{:else}
{@render blastoff()}
{/if}
{/snippet}
{@render countdown(10)}
コンポーネントへのスニペットの受け渡し
テンプレート内では、スニペットは他の値と同様に値です。そのため、コンポーネントに props として渡すことができます (デモ)
<script>
import Table from './Table.svelte';
const fruits = [
{ name: 'apples', qty: 5, price: 2 },
{ name: 'bananas', qty: 10, price: 1 },
{ name: 'cherries', qty: 20, price: 0.5 }
];
</script>
{#snippet header()}
<th>fruit</th>
<th>qty</th>
<th>price</th>
<th>total</th>
{/snippet}
{#snippet row(d)}
<td>{d.name}</td>
<td>{d.qty}</td>
<td>{d.price}</td>
<td>{d.qty * d.price}</td>
{/snippet}
<Table data={fruits} {header} {row} />
コンポーネントにデータではなくコンテンツを渡すようなものです。この概念は、Webコンポーネントのスロットに似ています。
オーサリングの便宜上、コンポーネントの*内部*で直接宣言されたスニペットは、暗黙的にコンポーネントの*上*の props になります (デモ)
<!-- this is semantically the same as the above -->
<Table data={fruits}>
{#snippet header()}
<th>fruit</th>
<th>qty</th>
<th>price</th>
<th>total</th>
{/snippet}
{#snippet row(d)}
<td>{d.name}</td>
<td>{d.qty}</td>
<td>{d.price}</td>
<td>{d.qty * d.price}</td>
{/snippet}
</Table>
スニペット宣言*ではない*コンポーネントタグ内のコンテンツは、暗黙的に `children` スニペットの一部になります (デモ)
<Button>click me</Button>
<script>
let { children } = $props();
</script>
<!-- result will be <button>click me</button> -->
<button>{@render children()}</button>
コンポーネント内にコンテンツがある場合、`children` という名前の prop を持つことはできません。このため、その名前の prop を使用することは避けるべきです。
スニペット props を省略可能として宣言できます。スニペットが設定されていない場合、オプショナルチェーンを使用して何もレンダリングしないようにすることができます...
<script>
let { children } = $props();
</script>
{@render children?.()}
...または、`#if` ブロックを使用してフォールバックコンテンツをレンダリングすることもできます。
<script>
let { children } = $props();
</script>
{#if children}
{@render children()}
{:else}
fallback content
{/if}
スニペットの型付け
スニペットは、`'svelte'` からインポートされた `Snippet` インターフェースを実装します。
<script lang="ts">
import type { Snippet } from 'svelte';
interface Props {
data: any[];
children: Snippet;
row: Snippet<[any]>;
}
let { data, children, row }: Props = $props();
</script>
この変更により、`data` prop と `row` スニペットを提供せずにコンポーネントを使用しようとすると、赤い波線が表示されます。`Snippet` に提供される型引数はタプルであることに注意してください。これは、スニペットが複数の引数を持つことができるためです。
ジェネリックを宣言することで、`data` と `row` が同じ型を参照するように、さらに厳密にすることができます。
<script lang="ts" generics="T">
import type { Snippet } from 'svelte';
let {
data,
children,
row
}: {
data: T[];
children: Snippet;
row: Snippet<[T]>;
} = $props();
</script>
スニペットのエクスポート
`.svelte` ファイルのトップレベルで宣言されたスニペットは、他のコンポーネントで使用するために `<script module>` からエクスポートできます。ただし、非モジュール `<script>` 内の宣言を(直接的または間接的に、他のスニペットを介して)参照していない場合に限ります (デモ)
<script module>
export { add };
</script>
{#snippet add(a, b)}
{a} + {b} = {a + b}
{/snippet}
これには Svelte 5.5.0 以後が必要です。
プログラムによるスニペット生成
スニペットは、`createRawSnippet` API を使用してプログラムで作成できます。これは高度なユースケースを想定しています。
スニペットとスロット
Svelte 4 では、スロットを使用してコンポーネントにコンテンツを渡すことができます。スニペットはより強力で柔軟性があるため、Svelte 5 ではスロットは非推奨となっています。