メインコンテンツにスキップ

{#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` スニペットの一部になります (デモ)

App
<Button>click me</Button>
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 ではスロットは非推奨となっています。

GitHub でこのページを編集する