Components and layouts
Compose child markup with slots
Let a parent provide HTML content for a component to place inside its own structure.
A slot is a hole in a component that the parent fills with its own markup.
Props pass values. Slots pass HTML. When a component needs a title, use a prop. When it needs a paragraph with a link inside, use a slot.
Here is a panel component in src/components/Panel.astro:
<aside class="panel">
<header><slot name="heading">Details</slot></header>
<slot />
</aside>
There are two slots. <slot name="heading"> is a named slot. <slot /> with no name is the default slot.
The parent fills both:
---
import Panel from '../components/Panel.astro'
---
<Panel>
<h2 slot="heading">Shipping</h2>
<p>Orders leave within two working days.</p>
</Panel>
The h2 goes into the heading slot because of its slot="heading" attribute. Everything else goes into the default slot. The rendered HTML is:
<aside class="panel">
<header><h2>Shipping</h2></header>
<p>Orders leave within two working days.</p>
</aside>
Fallback content
Details inside the heading slot is fallback content. Astro uses it only when the parent does not provide that slot. Write <Panel><p>Hello</p></Panel> and the header says “Details”.
This is handy for defaults that are markup, not text. A prop default can’t hold an icon and a label. A slot fallback can.
Props or slots?
My rule: use a prop when the component interprets the value. variant="warning" changes a class, so it’s a prop. Use a slot when the parent decides how the content looks. Links, emphasis, several elements. That’s a slot.
One element per named slot
In Astro 7, don’t assign several sibling elements to the same named slot. Only one of them renders. The others disappear silently, with no error.
Wrap the group in a Fragment:
<Fragment slot="heading">
<span>Shipping</span>
<small>Updated today</small>
</Fragment>
Fragment is a built-in that renders its children without a wrapper element. Now the whole group lands in the heading slot.
If a slot ever comes out with half the content missing, check for this first. It bit me on this very site after upgrading to Astro 7.
Layouts use the same mechanism. The layout owns the document shell and provides a <slot />. Each page supplies its own content. That’s the next lesson.
Lesson completed