Skip to main content

{#snippet ...}

{#snippet name()}...{/snippet}
{#snippet name(param1, param2, paramN)}...{/snippet}

Snippet と render タグ を使用すると、コンポーネント内で再利用可能なマークアップのチャンクを作成することができます。このような重複が多いコード を書く代わりに...

{#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}

関数宣言と同様に、snippet は任意の数のパラメーターを持つことができ、それぞれにデフォルト値を設定したり、分割代入を使用することができます。ただし、残余引数 (rest parameters) は使用できません。

Snippet scope

Snippets can be declared anywhere inside your component. They can reference values declared outside themselves, for example in the <script> tag or in {#each ...} blocks...

<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')}
<script lang="ts">
	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')}

...また、同じレキシカルスコープ内のすべての要素 (つまり兄弟要素やその子要素) から '見える (visible)' 状態になります:

<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()}

Snippets can reference themselves and each other:

{#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)}

snippet をコンポーネントに渡す

Explicit props

Within the template, snippets are values just like any other. As such, they can be passed to components as 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} />
<script lang="ts">
	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} />
<script>
	let { data, header, row } = $props();
</script>

<table>
	{#if header}
		<thead>
			<tr>{@render header()}</tr>
		</thead>
	{/if}

	<tbody>
		{#each data as d}
			<tr>{@render row(d)}</tr>
		{/each}
	</tbody>
</table>

<style>
	table {
		text-align: left;
		border-spacing: 0;
	}

	tbody tr:nth-child(2n+1) {
		background: ButtonFace;
	}

	table :global(th), table :global(td) {
		padding: 0.5em;
	}
</style>
<script lang="ts">
	let { data, header, row } = $props();
</script>

<table>
	{#if header}
		<thead>
			<tr>{@render header()}</tr>
		</thead>
	{/if}

	<tbody>
		{#each data as d}
			<tr>{@render row(d)}</tr>
		{/each}
	</tbody>
</table>

<style>
	table {
		text-align: left;
		border-spacing: 0;
	}

	tbody tr:nth-child(2n+1) {
		background: ButtonFace;
	}

	table :global(th), table :global(td) {
		padding: 0.5em;
	}
</style>

Think about it like passing content instead of data to a component. The concept is similar to slots in web components.

Implicit props

As an authoring convenience, snippets declared directly inside a component implicitly become props on the component:

<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>

<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>
<script lang="ts">
	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>

<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>
<script>
	let { data, header, row } = $props();
</script>

<table>
	{#if header}
		<thead>
			<tr>{@render header()}</tr>
		</thead>
	{/if}

	<tbody>
		{#each data as d}
			<tr>{@render row(d)}</tr>
		{/each}
	</tbody>
</table>

<style>
	table {
		text-align: left;
		border-spacing: 0;
	}

	tbody tr:nth-child(2n+1) {
		background: ButtonFace;
	}

	table :global(th), table :global(td) {
		padding: 0.5em;
	}
</style>
<script lang="ts">
	let { data, header, row } = $props();
</script>

<table>
	{#if header}
		<thead>
			<tr>{@render header()}</tr>
		</thead>
	{/if}

	<tbody>
		{#each data as d}
			<tr>{@render row(d)}</tr>
		{/each}
	</tbody>
</table>

<style>
	table {
		text-align: left;
		border-spacing: 0;
	}

	tbody tr:nth-child(2n+1) {
		background: ButtonFace;
	}

	table :global(th), table :global(td) {
		padding: 0.5em;
	}
</style>

Implicit children snippet

Any content inside the component tags that is not a snippet declaration implicitly becomes part of the children snippet:

<script>
	import Button from './Button.svelte';
</script>

<Button>click me</Button>
<script lang="ts">
	import Button from './Button.svelte';
</script>

<Button>click me</Button>
<script>
	let { children } = $props();
</script>

<!-- 結果は <button>click me</button> となります -->
<button>{@render children()}</button>
<script lang="ts">
	let { children } = $props();
</script>

<!-- 結果は <button>click me</button> となります -->
<button>{@render children()}</button>

コンポーネント内にコンテンツがある場合、children という名前の props を持つことはできません — このため、その名前の props を避けるべきです。

Optional snippet props

snippet の props をオプションとして宣言することができます。snippet が設定されていない場合は、オプショナルチェーン (optional chaining) を使用して何もレンダリングしないようにするか...

<script>
	let { children } = $props();
</script>

{@render children?.()}

...または、#if ブロックを使用してフォールバックコンテンツをレンダリングすることができます:

<script>
	let { children } = $props();
</script>

{#if children}
	{@render children()}
{:else}
	fallback content
{/if}

snippet に型を付ける

snippet は、'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 プロパティと row snippet を提供せずにコンポーネントを使用しようとすると、赤い波線が表示されるようになります。snippet には複数のパラメーターを持たせることができるため、Snippet に提供される型引数がタプルになっていることに注意してください。

generic を宣言することで、datarow が同じ型を参照するように、さらに厳密にすることができます:

<script lang="ts" generics="T">
	import type { Snippet } from 'svelte';

	let {
		data,
		children,
		row
	}: {
		data: T[];
		children: Snippet;
		row: Snippet<[T]>;
	} = $props();
</script>

snippet をエクスポートする

Snippets declared at the top level of a .svelte file can be exported from a <script module> for use in other components, provided they don't reference any declarations in a non-module <script> (whether directly or indirectly, via other snippets):

<script>
	import { add } from './snippets.svelte';
</script>

{@render add(1, 2)}
<script lang="ts">
	import { add } from './snippets.svelte';
</script>

{@render add(1, 2)}
<script module>
	export { add };
</script>

{#snippet add(a, b)}
	{a} + {b} = {a + b}
{/snippet}

これには Svelte 5.5.0 以上が必要です

プログラマティックな snippet

snippet は、createRawSnippet API を使用してプログラムで作成することができます。これは高度なユースケースを意図しています。

Snippet と slot

Svelte 4 では、slot を使用してコンテンツをコンポーネントに渡すことができます。snippet はより強力で柔軟性があるため、Svelte 5 では slot は非推奨となりました。

Edit this page on GitHub llms.txt