Layout System
The layout system (src/layouts/) implements a shared data, different structure pattern where multiple layouts receive identical data but render it with different visual structures.
Core Concept
┌──────────────────────────────────────────────────────────────────┐
│ COMMON DATA PIPELINE │
│ site.yaml → [..slug].astro → loadContent() → Parser → HTML │
└────────────────────────────────┬─────────────────────────────────┘
│
│ Same props passed to all layouts
│
┌───────────────────────┼───────────────────────┐
▼ ▼ ▼
┌───────────┐ ┌───────────┐ ┌───────────┐
│doc_style1 │ │doc_style2 │ │doc_style3 │
│ │ │ │ │ │
│ Sidebar │ │ │ │ Sidebar │
│ Body │ │ Body │ │ Body │
│ Outline │ │ Outline │ │ │
└───────────┘ └───────────┘ └───────────┘
3-column 2-column 2-column
All doc layouts receive the same props:
{
title: string;
description: string;
dataPath: string; // For loading sidebar/settings
baseUrl: string; // For URL generation
currentSlug: string; // For active state highlighting
content: string; // Rendered HTML from parser
headings: Heading[]; // For outline/TOC
}
The difference is purely structural — which components are rendered and how they're arranged.
Layout Layer in Architecture
┌─────────────────────────────────────────────────────────────────────────┐
│ 4. LAYOUT LAYER │
│ │
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │
│ │ BaseLayout │ │ Layout Styles │ │ Components │ │
│ │ (HTML shell) │ │ @docs/style1 │ │ Sidebar, Body │ │
│ │ │ │ @blog/style1 │ │ Outline, etc. │ │
│ └────────┬────────┘ └────────┬────────┘ └────────┬────────┘ │
│ │ │ │ │
│ └─────────────────────┴─────────────────────┘ │
│ │ │
│ Composition │
└─────────────────────────────────────────────────────────────────────────┘
File Structure
src/layouts/
├── BaseLayout.astro # Root HTML structure (all pages)
│
├── docs/ # Documentation layouts
│ ├── styles/
│ │ ├── doc_style1/Layout.astro # 3-column: sidebar + body + outline
│ │ └── doc_style2/Layout.astro # 2-column: body + outline
│ └── components/ # Shared doc components
│ ├── sidebar/default/
│ ├── body/default/
│ ├── outline/default/
│ └── common/Pagination.astro
│
├── blogs/ # Blog layouts
│ ├── styles/
│ │ └── blog_style1/
│ │ ├── IndexLayout.astro # Blog listing page
│ │ └── PostLayout.astro # Single post page
│ └── components/
│ ├── body/
│ └── cards/
│
├── custom/ # Custom page layouts
│ ├── styles/
│ │ ├── home/Layout.astro
│ │ └── info/Layout.astro
│ └── components/
│ ├── hero/
│ └── features/
│
├── navbar/ # Navbar variants
│ ├── style1/index.astro
│ └── minimal/index.astro
│
└── footer/ # Footer variants
├── default/index.astro
└── minimal/index.astro
Key Principles
1. Composition Over Inheritance
Layouts compose from shared components rather than extending base classes:
<!-- doc_style1/Layout.astro -->
<div class="docs-layout three-column">
<Sidebar nodes={sidebarNodes} currentPath={currentPath} />
<Body title={title} content={content}>
<Pagination prev={prev} next={next} />
</Body>
<Outline headings={headings} />
</div>
2. Automatic Discovery
Layouts are discovered via glob patterns — no manual registry:
// In [...slug].astro
const docsLayouts = import.meta.glob('/src/layouts/docs/styles/*/Layout.astro');
const blogLayouts = import.meta.glob('/src/layouts/blogs/styles/*/*.astro');
Adding a new layout is just creating a folder with the right file.
3. Strict Validation
Missing or invalid layouts throw descriptive errors at build time:
[LAYOUT ERROR] Docs layout "doc_style99" does not exist.
Page: docs
Config: @docs/doc_style99
Expected: src/layouts/docs/styles/doc_style99/Layout.astro
Available: doc_style1, doc_style2
4. Standardized Paths
All layout types follow a consistent path pattern:
src/layouts/{type}/styles/{style}/Layout.astro
| Type | Pattern | Example |
|---|---|---|
| Docs | docs/styles/{style}/Layout.astro |
doc_style1 |
| Blog | blogs/styles/{style}/*.astro |
blog_style1 |
| Custom | custom/styles/{style}/Layout.astro |
home |
Data Flow Summary
1. [..slug].astro reads page config from site.yaml
│
▼
2. loadContentWithSettings() loads all content + folder settings
│
▼
3. buildSidebarTree() creates navigation structure
│
▼
4. Layout receives standardized props
│
▼
5. Layout composes components (Sidebar, Body, Outline)
│
▼
6. BaseLayout wraps with Navbar + Footer
│
▼
7. Final HTML output