まくろぐ
更新: / 作成:

スロットの基本 <slot />

Svelte コンポーネントを使用するときに子要素として渡した内容は、Svelte コンポーネントの中から <slot /> で参照することができます。 <slot /> の仕組みは、Vue.js や Astro でも採用されています(React.js では children prop で参照します)。

次の ExtLink コンポーネントは、外部サイトへのリンクを表示するコンポーネントの実装例です。

src/lib/ExtLink.svelte
<script lang="ts">
	export let href: string;
</script>

<a {href} target="_blank" rel="noopener noreferrer"><slot /></a>

この ExtLink コンポーネントは次のように使用します。

src/routes/+page.svelte
<script lang="ts">
	import ExtLink from '$lib/ExtLink.svelte';
</script>

<h1>Hello</h1>
<ExtLink href="https://www.bing.com/">Bing</ExtLink>

この例では、コンポーネント内の <slot /> という部分に Bing というテキストが展開されることになります。 よって、リンク部分は次のような HTML にコンパイルされます。

<a href="https://www.bing.com/" target="_blank" rel="noopener noreferrer">Bing</a>

名前付きスロット <slot name=“name” />

子要素を複数のパートに分けてコンポーネントに渡したいことがあります。 このような場合は、名前付きスロット という仕組みを使います。 次の Box コンポーネントは、3 つのスロットを受け取れるようにしています。

  • header という名前のスロット
  • 名前なしスロット
  • footer という名前のスロット
src/lib/Box.svelte
<div class="container">
	<div class="header">
		<slot name="header">No header was provided</slot>
	</div>
	<div class="body">
		<slot />
	</div>
	<div class="footer">
		<slot name="footer" />
	</div>
</div>

<style>
	.container {
		display: flex;
		flex-direction: column;
		gap: 1rem;
		width: 300px;

		color: #333;
		border: 1px solid #333;
		border-radius: 0.5rem;
		box-shadow: 2px 2px 8px rgba(0, 0, 0, 0.2);
		padding: 1em;
	}
	.header {
		font-size: 1.5rem;
	}
	.footer {
		color: #666;
	}
</style>

この Box コンポーネントを使うときは、次のように何らかの要素の slot prop でどのスロットに子要素を渡すかを指定します。

Box コンポーネントの使用例
<script lang="ts">
	import Box from '$lib/Box.svelte';
</script>

<Box>
	<div slot="header">ヘッダーテキスト</div>
	<p>本文 本文 本文 本文 本文 本文 本文</p>
	<p>本文 本文 本文 本文 本文 本文 本文</p>
	<p>本文 本文 本文 本文 本文 本文 本文</p>
	<div slot="footer">フッターテキスト</div>
</Box>
/p/gcdawrj/img-001.png
図: Box コンポーネントの表示例

これで目的は達成されているように見えるのですが、名前付きスロットを使うときに slot prop を指定するための余計な div 要素が追加されています。 余計な div 要素を追加しないようにするには、代わりに svelte:fragment という要素を使います。

Box コンポーネントの使用例(修正版)
<script lang="ts">
	import Box from '$lib/Box.svelte';
</script>

<Box>
	<svelte:fragment slot="header">ヘッダーテキスト</svelte:fragment>
	<p>本文 本文 本文 本文 本文 本文 本文</p>
	<p>本文 本文 本文 本文 本文 本文 本文</p>
	<p>本文 本文 本文 本文 本文 本文 本文</p>
	<svelte:fragment slot="footer">フッターテキスト</svelte:fragment>
</Box>

関連記事

まくろぐ
サイトマップまくへのメッセージ