Layouts, Slots & Component Composition
Every page written so far has repeated its own <html>/<head>/<body> boilerplate. A layout is just an ordinary Astro component, conventionally kept in src/layouts/, that wraps a page's own content instead.
A Basic Layout
Whatever's placed between <BaseLayout> and </BaseLayout> in the page renders wherever <slot /> appears inside the layout itself. title is passed as an ordinary prop, same as any other component — a layout isn't a special kind of file, just a component used in this particular role by convention.
<slot /> is modeled directly on the native browser Web Component slotting API — the same underlying concept the HTML platform itself provides. React's children is just a plain prop with no dedicated syntax; Vue's own <slot> element is closer in spirit to Astro's own, both drawing from the same native idea.
Named Slots
An element with a slot="name" attribute is routed into the matching named <slot name="..." />; everything else falls into the unnamed default slot.
Nesting Layouts
A layout can wrap another layout — BlogPostLayout adds blog-specific chrome (a publish date) around its own <slot />, while still passing through to BaseLayout for the shared <html> shell. Layouts compose the same way any other Astro components do.
Slots, Compared Across Frameworks
| Framework | Mechanism |
|---|---|
| React | The children prop — a plain JavaScript value, no dedicated syntax |
| Vue | <slot>, named via <template #name> |
| Svelte 5 | Snippet props rendered via {@render children()} — replaced the older <slot> mechanism used in Svelte 3/4 |
| Astro | <slot /> and named <slot name="..." />, modeled on the native Web Component API |
Coding Challenges
Build BaseLayout.astro with a full HTML shell, a title prop for the <title> tag, and a default <slot />, then use it from index.astro.
📄 View solutionAdd a named "sidebar" slot to BaseLayout, and pass sidebar content into it from a page using slot="sidebar", alongside default-slot main content.
📄 View solutionBuild a BlogPostLayout.astro that wraps BaseLayout and adds a publishDate prop rendered above its own <slot />, then use it from a blog post page.
📄 View solutionChapter 4 Quick Reference
src/layouts/— an ordinary component used by convention to wrap a page's own content<slot />— the default insertion point, modeled on the native Web Component slotting API<slot name="..." />/slot="..."— named slots for multiple distinct insertion points- Layouts are just components — they take props and can wrap other layouts
- Genuine cross-framework difference — React's plain
childrenprop vs. Vue/Astro's native-style<slot>vs. Svelte 5's newer snippet-based{@render} - Next chapter: Content Collections