🧊

Astroで名前付きスロットが使えるのは、同系統のコンポーネント間だけ

つまり、名前付きスロットを`.astro`なコンポーネントで使うとき、

---
import Layout from "...";
---

<Layout>
  <h2 slot="after-header">After header</h2>
  <h2>Default slot</h2>
  <h2 slot="after-footer">After footer</h2>
</Layout>

これが想定通りに動作するのは、`Layout`コンポーネントも`.astro`のときだけ、という話。

たとえば`Layout`コンポーネントが`.svelte`だったりすると、名前付きスロットに渡したコンポーネントが表示されないのです。(それどころか、名前なしスロットの部分まで表示されなかったりする)

ちなみに、Astroのバージョンは`1.0.0-beta.17`のときの話です

仕様らしい

🐛 BUG: Named Slots are not forwarded to Svelte Components · Issue #2238 · withastro/astro · GitHub

コンパイラの仕様なら仕方ないか・・とは思いつつ。

まとめると、

Where Layout Works?
.astro .astro Yes
.astro .svelte/.vue No
.svelte .svelte Yes
.vue .vue Yes

ってこと。

もちろん`.svelte`の中では、他のタイプのコンポーネントは読み込めない。

名前付きではないただのスロットなら使えるし、他のタイプ同士を混ぜ込むことすらできる。

https://docs.astro.build/en/core-concepts/framework-components/#nesting-framework-components

ワークアラウンド

幸い自分のケースは軽傷で、こんな風なコンポーネントを`.svelte`で作ってた。

<div class="layout">
  <div>
    <slot name="main" />
  </div>
  <div>
    <slot name="sub" />
  </div>
</div>

<style>
  .layout {
    display: grid;
    grid-template-columns: 1fr 300px;
    gap: 16px;
  }
</style>

というように、2カラムにしたいだけだった。
なので、名前付き`slot`を使わずに、単一の`slot`だけでもなんとかなった。

<div class="layout">
  <slot />
</div>

<style>
  .layout {
    display: grid;
    grid-template-columns: 1fr 300px;
    gap: 16px;
  }
</style>

使う側はこう。

<Layout>
  <Main />
  <Sub />
</Layout>

ただし、`Main`も`Sub`も単一の要素を返すという暗黙の前提が生まれてしまうけど・・・。

Render propsもダメ

`.astro`はJSXモドキなので、Propsでコンポーネントごと渡せばワンチャンあるか?!って思ったけど、ぜんぜんダメだった。

<Layout
  main={<Main />}
  sub={<Sub />}
/>

めちゃめちゃコンパイルエラーがでた。

おとなしくレイアウトは`.astro`でやれって話でした。