---
title: "Sidebar"
description: "Autogenerate, configure, or transform the sidebar tree with custom groups, links, order, and badges."
---

> Documentation Index
> Fetch the complete documentation index at: https://nimbus-docs.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Sidebar

Nimbus builds a typed sidebar tree from your content. Start with the filesystem, take control with configuration, or transform the final tree for navigation that depends on application data or the current route.

## Order and label pages

The sidebar is generated from `src/content/docs/` by default. Set `sidebar.items` in `astro.config.ts` only when you need to override that structure. Use `sidebar.order` in a page's frontmatter, such as `src/content/docs/guides/install.mdx`, to control ordering; otherwise entries are alphabetical.

```yaml title="src/content/docs/guides/install.mdx"
---
title: Install the CLI
sidebar:
  order: 1
  label: Install
  badge:
    text: New
    variant: tip
---
```

Frontmatter can also hide entries, customize directory groups, redirect links, or collapse a section. See [Hide or change one page's entry](#hide-or-change-one-pages-entry).

## Arrange the sidebar by hand

In `astro.config.ts`, use `sidebar.items` when the filesystem should not define the entire rail. Config items can be nested and can mix manual links with generated content:

```ts title="astro.config.ts"
sidebar: {
  items: [
    "introduction",
    { label: "GitHub", link: "https://github.com/you/repo" },
    {
      label: "Guides",
      autogenerate: { directory: "guides" },
      collapsed: false,
      badge: "New",
      icon: "ph:book-open",
    },
    {
      label: "API",
      autogenerate: { collection: "api" },
      icon: "ph:code",
    },
    {
      label: "AI",
      segment: "/ai",
      landing: "/ai/models",
      items: [
        { label: "Models", link: "/ai/models" },
        { autogenerate: { directory: "ai/guides" } },
      ],
    },
  ],
}
```

| Shape | Use |
|---|---|
| `"slug"` | Link one page from the primary collection. |
| `{ label, link }` | Add a labeled internal or external link. |
| `{ autogenerate: { directory } }` | Generate a group from one content directory. |
| `{ autogenerate: { collection, prefix? } }` | Mount another registered collection, linked where it's served ([Collection URLs](/writing/collections#collection-urls)). `prefix` sets the URL for a collection served by your own route, not a Nimbus route helper; for one that is, the route sets the URL and `prefix` is deprecated. |
| `{ label, items }` | Build a recursive manual group. Groups support `collapsed`, `badge`, and `icon`. |
| `{ segment, landing }` | Give a manual group ownership of a URL segment while linking its label and breadcrumbs to a real landing page. |

Array position controls manual item order. Nimbus does not re-sort a configured or transformed array.

## Show a collection inside a folder

A collection served inside a docs folder's URL appears in that folder. Take `src/content/docs/integrations/connectors/` and a `dbt` collection routed at `src/pages/integrations/connectors/dbt/[...slug].astro` (see [Collection URLs](/writing/collections#collection-urls)). dbt becomes a group inside Connectors, with `/integrations/connectors/dbt/` as its landing.

Breadcrumbs and previous and next links follow, because they read the sidebar. A page the sidebar leaves out gets the breadcrumbs of the deepest group above its URL.

This works wherever the folder is generated, by default or with `autogenerate`, but never among a hand-made group's own items.

If folders in between are missing, the collection goes in the deepest one that exists. A folder whose only page is its `index` becomes a group to hold it, keeping that page's label.

The collection's own `index` page controls the group, as a folder's does. Set its label and position:

```yaml title="src/content/dbt/index.mdx"
---
title: dbt
sidebar:
  order: 2              # its position among the folder's pages; pages with an order come first,
                        # and a group without one takes its lowest child's
  group:
    label: dbt Core     # the group label; the title otherwise
---
```

With no `index` page, the group is a heading named after the URL's last segment (`Dbt`). Show only its landing link with `sidebar.hideChildren: true`, or leave the whole collection out of the sidebar, along with any collection served inside it, with `sidebar.hidden: true`.

To place it yourself, name it in `sidebar.items`; it then appears only there:

- **`{ autogenerate: { collection: "dbt" }, label: "dbt" }`** shows its pages as a group with its landing. Without `label`, its pages go straight into the surrounding group, and its landing isn't linked.
- **`{ label: "dbt", link: "/integrations/connectors/dbt/" }`**, or a hand-made group's `landing`, shows only its landing page.

Not placed:

- a collection one segment deep (`/blog`), whose parent is the site root;
- an API collection, which has its own navigation;
- anything on another docs version's pages;
- a collection's alias routes (only the URL it's served at counts).

In `astro dev`, edits to a placed collection's pages under `src/content` show on reload. A collection loaded from elsewhere, or from a content source, shows changes to its navigation after a restart.

## Show only the current section

A site with many sections overflows a rail that lists everything. Set `scope: "section"` and each page's rail shows only its own top-level group:

```ts title="astro.config.ts"
sidebar: {
  scope: "section",
}
```

A section is a top-level group that lists another collection, written `autogenerate: { collection: "api" }`. Groups of the main docs collection's own pages, by `directory` or `items`, aren't sections.

With two or more sections, the starter's header shows them as tabs: in the bar on wide screens, and on a row of their own on phones. It builds them from the same tree with `getSidebarSections()`, and a header of your own can too:

```astro
---
import { getSidebarSections } from "@cloudflare/nimbus-docs";

const sections = await getSidebarSections(currentSlug, {
  collection: entry.collection,
});
---
```

`scope: "full"`, the default, renders the complete tree on every page.

## Give a deep folder its own sidebar

When one section is itself large, such as a reference with a folder per product, scope the rail one level deeper. List the folders that should get their own rail as segment globs, where `*` matches one path segment:

```ts title="astro.config.ts"
sidebar: {
  scope: "section",
  isolate: { boundaries: ["reference/*"] },
}
```

A page under `/reference/cli/` now shows only the `reference/cli` group. Pages outside a boundary keep the section rail. The rail starts with the group's landing page, labeled like an overview leaf under `indexDisplay: "overview-leaf"`.

## Collapse groups until they're needed

A long rail is easier to scan when its groups start closed. Set `defaultCollapsed: true`:

```ts title="astro.config.ts"
sidebar: {
  defaultCollapsed: true,
}
```

The group holding the current page still opens. A group with its own `collapsed: false` in `sidebar.items` stays open, so a "Start here" group can stay visible while the rest close.

## Choose how group landing pages appear

A directory `index.mdx` is its group's landing page. Configure how those landings appear across the site in `astro.config.ts`:

```ts title="astro.config.ts"
sidebar: {
  indexDisplay: "overview-leaf",
  overviewLabel: "Overview",
}
```

| Option | Behavior |
|---|---|
| `indexDisplay: "header-link"` | Default. The group heading links to its landing page. |
| `indexDisplay: "overview-leaf"` | The group heading becomes a disclosure and the landing becomes its first child. |
| `overviewLabel: true` | Labels landing links `Overview`. A string supplies a custom label. |
| `sidebar.group.hideIndex: true` | Keeps the page built but makes its group heading non-interactive. |
| `sidebar.hideChildren: true` | Collapses the whole directory to one link to its landing page. |

## Change the sidebar per page

Configuration defines the structural tree. `getSidebar()` also accepts a synchronous or asynchronous `transform` for computed navigation. It runs after scope and isolation, but before `indexDisplay` reshapes landing pages.

```astro title="src/pages/[...slug].astro"
---
import { getPrevNext, getSidebar } from "@cloudflare/nimbus-docs";

const sidebar = await getSidebar(currentSlug, {
  collection: entry.collection,
  transform: ({ tree, sectionSlug }) => {
    if (sectionSlug !== "api") return tree;

    return tree.map((item) =>
      item.type === "group" && item.label === "Reference"
        ? {
            ...item,
            collapsed: false,
            badge: "API",
            children: [
              ...item.children,
              {
                type: "external",
                label: "API status",
                href: "https://status.example.com",
                order: Number.MAX_SAFE_INTEGER,
              },
            ],
          }
        : item,
    );
  },
});

const prevNext = await getPrevNext(currentSlug, {
  sidebarTree: sidebar,
});
---
```

The callback receives:

| Value | Meaning |
|---|---|
| `tree` | The cloned, active-state-aware `SidebarItem[]` for this page. Nodes are `link`, `external`, or recursive `group` items. |
| `currentSlug` | The complete current URL path. |
| `sectionSlug` | The first path segment. |
| `module` | The second path segment, when present. |
| `indexEntryId` | The active section group's landing entry ID, when it has one. |

A transform can fetch data, insert or remove nodes, rewrite nested groups, attach badges, or reorder the rail. Return rendered `SidebarItem` nodes, not config-only shapes such as `autogenerate`. Preserve existing properties when decorating nodes, and pass the result to `getPrevNext()` when pagination should follow the transformed order.

Transforms only affect the page rail. Breadcrumbs and `getSidebarSections()` continue to use the structural tree.

## Hide or change one page's entry

Use frontmatter for local changes:

| Field | Behavior |
|---|---|
| `sidebar: false` | Removes the sidebar column from this page. |
| `sidebar.order` | Orders an entry inside an autogenerated group. |
| `sidebar.label` | Overrides the page title in the rail. |
| `sidebar.badge` | Adds a string or styled badge. |
| `sidebar.hidden` | Builds the page but removes it from the rail. |
| `sidebar.group.label` | Overrides the directory group's label from its `index.mdx`. |
| `sidebar.group.badge` | Adds a badge to the directory group. |
| `sidebar.group.icon` | Adds an `astro-icon` icon to the directory group. |
| `sidebar.group.hideIndex` | Prevents the directory group heading from linking to its index. |
| `sidebar.hideChildren` or `hideChildren` | Collapses the directory to its landing link. |
| `external_link` | Points the entry at another internal path or an absolute URL. The page still builds at its own path, and absolute URLs open in a new tab. |

Set `features.sidebar: false` in `astro.config.ts` to disable the rail site-wide. See [Frontmatter](/reference/frontmatter) for complete field shapes and badge variants.

## Restyle sidebar rows

Sidebar groups are native `<details>`/`<summary>` elements: opening and closing needs no JavaScript, links in closed groups stay in the HTML for find-in-page and crawlers, and closed lists carry `display: none` so large trees stay fast. A group with a landing page lists it as the group's first child, labelled "Overview" — the summary row is label-only.

Rows carry no class or data attribute, so a sidebar of thousands of pages stays light. The "Sidebar rows" section of `src/styles/globals.css` styles them by position inside the sidebar (`[data-nb-sidebar]`, and `[data-nb-api-nav]` for the API reference). Edit those rules to restyle every row. They sit in Tailwind's `components` layer, so a Tailwind utility on a row still overrides them:

| Selector | Element |
|---|---|
| `[data-nb-sidebar] li > a` | A leaf row: `<a href>Label</a>`. The current page carries `aria-current="page"`. |
| `[data-nb-sidebar] details > summary` | A group's row. The caret is its `::after` mask, rotated by `details[open]`; the active trail carries `data-nb-active`. |
| `[data-nb-sidebar] details > ul` | A group's child list. |
| `i[data-m]` | An API operation's method chip; `data-m` is the lowercase method. |

Each page renders one sidebar tree: the mobile drawer borrows the rail's tree while it is open and returns it on close, so open groups, the filter, and scroll position stay with you across the breakpoint.

Source: https://nimbus-docs.com/navigation/sidebar/index.mdx
