スロットの基本 <slot />
Svelte コンポーネントを使用するときに子要素として渡した内容は、Svelte コンポーネントの中から <slot />
で参照することができます。
<slot />
の仕組みは、Vue.js や Astro でも採用されています(React.js では children
prop で参照します)。
次の ExtLink
コンポーネントは、外部サイトへのリンクを表示するコンポーネントの実装例です。
<script lang="ts">
export let href: string;
</script>
<a {href} target="_blank" rel="noopener noreferrer"><slot /></a>
この ExtLink
コンポーネントは次のように使用します。
<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
という名前のスロット
<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 でどのスロットに子要素を渡すかを指定します。
<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>

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