---
title: Customizing the layout
description: Compose the render primitives instead of using the default shell.
---

`DocsShell` renders a complete docs page: sidebar, article, table of contents, pager. It emits the whole document, `<head>` included. Most sites never need more.

```rust filename="src/pages/docs.rs"
use proa_docs::DocsShell;

DocsShell { docs, page }.render(cx)?;
```

`DocsShell` writes its own `<head>` (charset, viewport, title, description)
and has no slot for a stylesheet link, so the default theme only applies when
you compose your own head and render `DocsAssets` there, as shown in
[Styling](/docs/proa-docs/quickstart#styling). `DEFAULT_STYLESHEET` and
`DEFAULT_SCRIPT` are the bytes to serve for it.

When you want your own chrome, compose the pieces yourself.

## The primitives

| Component | Renders |
|---|---|
| `DocsShell` | The whole page. Start here |
| `DocsNav` | The sidebar tree for a path |
| `DocsNavItem` | One nav entry, if you are building the tree yourself |
| `DocsSectionMenu` | The section switcher, when any folder is a root |
| `DocsToc` | On-this-page headings |
| `DocsPager` | Previous and next links |
| `TypeTable` | An API table from rows your app supplies; the build does not produce them |
| `nav_icon_svg` | An icon by name, for your own chrome |

Apart from `TypeTable`, each takes data from the compiled `Docs` registry, so they stay in sync with content without threading state.

## Replacing one piece

Keep the primitives, wrap them in your own markup. This is what the Proa site does — its sidebar adds a logo, a search trigger, and a theme toggle around the same `DocsNav` you would use:

```rust filename="src/components/docs/sidebar.rs"
use proa_docs::{DocsNav, DocsSectionMenu};

html_sync! {
    <div class="docs-sidebar-inner">
        <div class="docs-sidebar-header">
            {SearchTrigger { class: Some("docs-sidebar-search") }}
            {DocsSectionMenu { docs, active_path: page.route_path }}
        </div>
        <div class="docs-sidebar-content">
            {DocsNav {
                items: docs.nav_items_for_path(page.route_path),
                active_path: page.route_path,
            }}
        </div>
    </div>
}
```

`proa_marketing/src/components/docs/` in the Proa repository is the full worked example — sidebar, article, and page, each wrapping primitives rather than replacing them.

## Reading the registry directly

For chrome the primitives do not cover, walk the model:

| Type | Holds |
|---|---|
| `Docs` | Config, every page, the nav tree, search artifacts |
| `DocPage` | Slug, route, title, description, article HTML, TOC, prev/next |
| `NavItem` | One nav node: page, group, separator, or root |
| `TocItem` | Depth, id, title |

```rust filename="src/pages/docs.rs"
let page = docs.page_for_path(path)?;
let items = docs.nav_items_for_path(page.route_path);
```

`nav_items_for_path` returns a root section's children when the path is inside one, and the whole tree otherwise. That single call is what makes the section switcher work.

## Styling what you build

The primitives emit stable class and `data-` hooks, all documented in [Styling contract](/docs/proa-docs/styling-contract). Your own wrapper markup is yours to style; the parts you compose keep working with the default theme.

## Related

[Rendering pages](/docs/proa-docs/runtime) · [Styling contract](/docs/proa-docs/styling-contract) · [Navigation](/docs/proa-docs/navigation)
