DocsLayout
The page shell — composes navbar, sidebar, content, and ToC into a single React tree.
DocsLayout
DocsLayout is the outermost wrapper around any docs page. It doesn't do much visually — instead, it splits the screen into named, themed slots that the rest of the UI hooks into. Most custom layouts only need to swap two or three of its sub-components.
The default implementation in Boltdocs already wires Navbar, Sidebar, OnThisPage, breadcrumbs, and so on. You don't need to use it. But if you're building a custom theme, copying the assembly pattern is the fastest way to get consistent spacing, scrolling, and z-index behavior for free.
Import
import { DocsLayout } from 'boltdocs/primitives'
The mental model
Every Boltdocs page has seven regions that plugin authors and custom layouts may want to write into:
┌─ Navbar ──────────────────────────────────────────┐ ← sticky top
├─ Body ─────────────────────────────────────────────┤
│ ┌─ Sidebar ─┐ ┌─ Content ────────┐ ┌─ ToC ────┐ │
│ │ │ │ ┌─ Header ──┐ │ │ │ │
│ │ │ │ │ crumbs │ │ │ │ │
│ │ │ │ │ title │ │ │ │ │
│ │ │ │ └───────────┘ │ │ │ │
│ │ │ │ ┌─ MDX ───────┐ │ │ │ │
│ │ │ │ │ ...children │ │ │ │ │
│ │ │ │ └─────────────┘ │ │ │ │
│ │ │ │ ┌─ Footer ───┐ │ │ │ │
│ │ │ │ │ PageNav │ │ │ │ │
│ │ │ │ └────────────┘ │ │ │ │
│ └───────────┘ └──────────────────┘ └───────────┘ │
└───────────────────────────────────────────────────┘
Floating elements outside this tree:
• FloatingBottom — bubble pinned to viewport corner
• RightRail — vertical column on lg+ viewports
• BodyPortal — `createPortal` to `document.body`
DocsLayout exposes one named sub-component per region. Inside your custom layout, you decide which ones get a Navbar, which one gets a Sidebar, etc.
Sub-components
| Sub-component | Renders | Purpose |
|---|---|---|
DocsLayout (root) | <div> | The outer flex column container. Sets app-wide background, scrolling, and color defaults. |
DocsLayout.Body | <div> | The horizontal row that holds Sidebar + Content + ToC. |
DocsLayout.Content | <main> | The scrollable middle column. The actual page goes here. |
DocsLayout.ContentMdx | <div> | An inner padded wrapper that constrains content to a max-width reading column. |
DocsLayout.Header | <header> | Above-body section. Best home for breadcrumbs + page title + description. |
DocsLayout.Footer | <div> | Below-body section. Best home for PageNav. |
DocsLayout.FloatingBottom | <div> (fixed) | Pinned to bottom-6 right-6. Hosts floating widgets like "Ask AI" buttons. |
DocsLayout.RightRail | <aside> (fixed) | Vertical column on the right edge on xl+ viewports. Persistence + scrollable. |
DocsLayout.BodyPortal | <div> | Anything you wrap here is portalled into document.body. Modals, toasts, global overlays. |
Every sub-component accepts children, className, and style. There are no surprise props — they're extensions of a minimal HTML pass-through.
Minimal layout
The smallest layout that makes sense: a navbar at the top and the page content in the middle. The Sidebar and OnThisPage are optional.
// my-docs/layout.tsx
import { DocsLayout, Navbar } from 'boltdocs/primitives'
export default function MyLayout({ children }: { children: React.ReactNode }) {
return (
<DocsLayout>
<Navbar>...</Navbar>
<DocsLayout.Body>
<DocsLayout.Content>
<DocsLayout.ContentMdx>{children}</DocsLayout.ContentMdx>
</DocsLayout.Content>
</DocsLayout.Body>
</DocsLayout>
)
}
That's the entire page. Add Sidebar to the left, OnThisPage to the right, and you have a fully built docs site.
Real-world layout, with everything
The layout we ship as a default. It uses every named slot. Use it as a copy-paste starting point when you want to make a custom theme that still feels "stock Boltdocs":
// src/components/ProductionDocsLayout.tsx
import {
DocsLayout,
Navbar,
Sidebar,
OnThisPage,
Breadcrumbs,
PageNav,
ErrorBoundary,
} from 'boltdocs/primitives'
import { useRoutes } from 'boltdocs/client'
import { ProductionNavbar } from './ProductionNavbar'
import { ProductionSidebar } from './ProductionSidebar'
export function ProductionDocsLayout({ children }: { children: React.ReactNode }) {
const { currentRoute } = useRoutes()
return (
// 1. Outer shell — sets background + scroll behavior
<DocsLayout className="min-h-screen selection:bg-primary-500/10 selection:text-primary-500">
{/* The navbar lives outside DocsLayout.Body so it spans full width. */}
<ProductionNavbar />
{/* 2. Body row: sidebar + content + ToC */}
<DocsLayout.Body className="bg-main">
<ProductionSidebar />
<DocsLayout.Content className="scroll-smooth">
<DocsLayout.ContentMdx className="max-w-3xl px-4 pt-8 pb-24 mx-auto">
{/* 3. Page header — breadcrumbs + title + description */}
<DocsLayout.Header>
<Breadcrumbs />
{currentRoute?.title && (
<h1 className="text-4xl font-bold tracking-tight mt-4">
{currentRoute.title}
</h1>
)}
{currentRoute?.description && (
<p className="text-lg text-muted leading-relaxed mt-3">
{currentRoute.description}
</p>
)}
</DocsLayout.Header>
{/* 4. Article body — wrapped in an Error Boundary */}
<ErrorBoundary>
<article className="prose dark:prose-invert max-w-none">
{children}
</article>
</ErrorBoundary>
{/* 5. Footer — previous/next links */}
<DocsLayout.Footer className="mt-12">
<PageNav />
</DocsLayout.Footer>
</DocsLayout.ContentMdx>
</DocsLayout.Content>
{/* 6. Right rail — table of contents (sticky, scroll-spy) */}
<OnThisPage.Tree headings={currentRoute?.headings} />
</DocsLayout.Body>
{/* 7. Floating widgets — outside the body flex */}
<DocsLayout.FloatingBottom>
<AskAiBubble /> {/* e.g. from `@bdocs/plugin-ask-ai` */}
</DocsLayout.FloatingBottom>
<DocsLayout.RightRail>
<RightRailAskAiHistory />
</DocsLayout.RightRail>
{/* 8. Body portal — modal mounts, toast roots, etc. */}
<DocsLayout.BodyPortal>
<ToastContainer />
</DocsLayout.BodyPortal>
</DocsLayout>
)
}
A few details worth calling out:
Navbaris outsideDocsLayout.Body. That keeps the navbar full-width while everything else shares the constrained body row.FloatingBottom/RightRail/BodyPortalare outside the body flex. They're positioned withfixedso they can escape the layout flow.ErrorBoundarysits around the article body only. Crashes there won't hide the navbar, breadcrumbs, or footer.
Floating widgets & portals
The three "floating" sub-components behave differently from the others:
DocsLayout.FloatingBottomis aposition: fixedcontainer pinned bottom-right. Use it for chat bubbles, "back to top" buttons, or any small persistent widget.DocsLayout.RightRailis aposition: fixedvertical column on the right edge. Use it for chat histories, conversation sidebars, or persistent drawers that shouldn't be inside the article.DocsLayout.BodyPortalusescreatePortalto render its children intodocument.body. Use it when you need a modal/toast to escapeoverflow: hiddencontainers.
You don't have to mount them — they're all optional. Mount only what you use.
Common decisions
- Need a sticky ToC? Put
<OnThisPage.Tree>insideDocsLayout.Bodyon the right. Boltdocs already ships one; copy it for your theme. - Making the content narrower on mobile?
ContentMdxacceptsmax-w-{value}viaclassName. The default is unset — pass your own width. - Debugging a layout issue? Set a red border on each sub-component (
border border-red-500) and walk down the tree.
Where next
- The default layout is at
packages/core/src/client/components/docs-layout-default.tsx. It's the production source of truth for region placement and responsive breakpoints. - See the Custom Layouts guide for a step-by-step walkthrough on swapping the default out.
- Each sub-component has a matching primitive — see Navbar, Sidebar, OnThisPage, Breadcrumbs, PageNav, CodeBlock, ErrorBoundary for the full reference.