スロットの基本 <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>