Docs Components

Docs layouts compose from shared components located in src/layouts/docs/components/. These components can be mixed and matched to create different layout styles.

Component Directory

src/layouts/docs/components/
├── sidebar/
│   └── default/
│       ├── Sidebar.astro     # Main sidebar component
│       └── styles.css
│
├── body/
│   └── default/
│       ├── Body.astro        # Main content area
│       └── styles.css
│
├── outline/
│   └── default/
│       ├── Outline.astro     # Table of contents
│       └── styles.css
│
└── common/
    ├── Pagination.astro      # Prev/Next navigation
    └── styles.css

The sidebar renders hierarchical navigation from your docs structure.

File: src/layouts/docs/components/sidebar/default/Sidebar.astro

Props

interface Props {
  nodes: SidebarNode[];    // Mixed: items (root files) + sections (folders)
  currentPath: string;     // Current page URL
}

type SidebarNode = SidebarItem | SidebarSection;

interface SidebarItem {
  type: 'item';
  title: string;
  href: string;
  slug: string;
  position: number;
}

interface SidebarSection {
  type: 'section';
  title: string;                // Section display name
  slug: string;                 // URL slug
  href?: string;                // Optional link target
  position: number;             // Sort order
  collapsed: boolean;           // Initial state
  collapsible: boolean;         // Can collapse?
  children: SidebarNode[];
}

Usage

---
import Sidebar from '../../components/sidebar/default/Sidebar.astro';
import { buildSidebarTree } from '@/hooks/useSidebar';

const sidebarNodes = buildSidebarTree(content, baseUrl, dataPath);
const currentPath = `${baseUrl}/${currentSlug}`;
---

<Sidebar nodes={sidebarNodes} currentPath={currentPath} />

Features

  • Recursive rendering: Supports nested sections of any depth
  • Collapsible sections: Sections can be collapsed/expanded
  • Active state: Current page and parent sections highlighted
  • Keyboard navigation: Accessible with keyboard

Customization

Override styles in your layout's CSS:

/* Custom sidebar width */
.sidebar {
  width: 300px;
}

/* Custom active state */
.sidebar-item--active {
  background: var(--color-primary);
  color: white;
}

Body

The body component renders the main content area with title, description, and content.

File: src/layouts/docs/components/body/default/Body.astro

Props

interface Props {
  title: string;          // Page title
  description?: string;   // Optional description
  content: string;        // Rendered HTML
}

Usage

---
import Body from '../../components/body/default/Body.astro';
---

<Body title={title} description={description} content={content}>
  <!-- Slot for pagination or other footer content -->
  <Pagination prev={prev} next={next} />
</Body>

Structure

<main class="docs-content">
  <article class="docs-article">
    <header class="docs-header">
      <h1 class="docs-title">Title</h1>
      <p class="docs-description">Description</p>
    </header>

    <div class="docs-body">
      <!-- content HTML inserted here -->
    </div>

    <slot />  <!-- Pagination goes here -->
  </article>
</main>

Slot

The body component has a default slot for additional content below the main body:

<Body title={title} content={content}>
  <Pagination prev={prev} next={next} />
  <Feedback />  <!-- Custom component -->
</Body>

Outline

The outline component renders a table of contents from headings.

File: src/layouts/docs/components/outline/default/Outline.astro

Props

interface Props {
  headings: Heading[];    // Array of headings
  title?: string;         // Optional title (default: "On this page")
}

interface Heading {
  depth: number;          // 1-6
  slug: string;           // ID for linking
  text: string;           // Display text
}

Usage

---
import Outline from '../../components/outline/default/Outline.astro';

// Filter headings (typically h2 and h3)
const outlineHeadings = headings.filter(h => h.depth >= 2 && h.depth <= 3);
---

{outlineHeadings.length > 0 && (
  <Outline headings={outlineHeadings} title="On this page" />
)}

Features

  • Scroll spy: Highlights current section as you scroll
  • Smooth scroll: Clicking jumps to section smoothly
  • Indentation: Nested headings are indented
  • Sticky positioning: Stays visible while scrolling

Filtering Headings

Control which headings appear via settings:

const outlineLevels = settings.outline?.levels || [2, 3];
const outlineHeadings = headings.filter(h => outlineLevels.includes(h.depth));

Pagination

The pagination component renders prev/next navigation links.

File: src/layouts/docs/components/common/Pagination.astro

Props

interface Props {
  prev?: NavigationItem | null;
  next?: NavigationItem | null;
}

interface NavigationItem {
  title: string;    // Display text
  href: string;     // Link URL
}

Usage

---
import Pagination from '../../components/common/Pagination.astro';
import { getPrevNext } from '@/hooks/useSidebar';

const { prev, next } = getPrevNext(sidebarSections, currentPath);
---

{(prev || next) && (
  <Pagination prev={prev} next={next} />
)}

Structure

<nav class="pagination">
  <a href="/docs/previous" class="pagination__link pagination__link--prev">
    <span class="pagination__direction">← Previous</span>
    <span class="pagination__title">Previous Page Title</span>
  </a>

  <a href="/docs/next" class="pagination__link pagination__link--next">
    <span class="pagination__direction">Next →</span>
    <span class="pagination__title">Next Page Title</span>
  </a>
</nav>

Creating Custom Components

You can create custom component variants:

1. Create Component Folder

mkdir -p src/layouts/docs/components/sidebar/modern/

2. Create Component

---
// src/layouts/docs/components/sidebar/modern/Sidebar.astro
interface Props {
  nodes: SidebarNode[];    // Mixed: items (root files) + sections (folders)
  currentPath: string;
}

const { nodes, currentPath } = Astro.props;
---

<nav class="modern-sidebar">
  <!-- Your custom implementation -->
</nav>

<style>
  .modern-sidebar {
    /* Your styles */
  }
</style>

3. Use in Layout

---
// In your layout
import Sidebar from '../../components/sidebar/modern/Sidebar.astro';
---

Component Composition Example

Here's how doc_style1 composes components:

---
import Sidebar from '../../components/sidebar/default/Sidebar.astro';
import Body from '../../components/body/default/Body.astro';
import Outline from '../../components/outline/default/Outline.astro';
import Pagination from '../../components/common/Pagination.astro';

// Import styles
import '../../components/sidebar/default/styles.css';
import '../../components/body/default/styles.css';
import '../../components/outline/default/styles.css';
import '../../components/common/styles.css';
import './layout.css';

// ... props and data loading ...
---

<div class="docs-layout">
  <Sidebar nodes={sidebarNodes} currentPath={currentPath} />

  <Body title={title} description={description} content={content}>
    {paginationEnabled && <Pagination prev={prev} next={next} />}
  </Body>

  {outlineEnabled && <Outline headings={outlineHeadings} />}
</div>

The layout CSS handles the grid arrangement:

/* layout.css */
.docs-layout {
  display: grid;
  grid-template-columns: 280px 1fr 220px;
  gap: 2rem;
  max-width: 1400px;
  margin: 0 auto;
}