CmdocsCmdocs
Configuration

Navigation

Define your sidebar tabs, groups, and pages — plus navbar links.

Navigation

Navigation in cmdocs has two parts:

  • Sidebar — controlled by the navigation field. Uses a tabs → groups → pages hierarchy.
  • Navbar links — controlled by navbar.links. The links shown across the top of the page.

Labels and paths

cmdocs separates display labels (what readers see) from URL paths (what appears in the address bar). This keeps URLs stable when you rename sections.

docs.json
{
  "navigation": {
    "tabs": [
      {
        "label": "Documentation",
        "path": "documentation",
        "groups": [
          {
            "label": "Getting Started",
            "pages": [
              { "file": "index" },
              { "file": "quickstart" }
            ]
          }
        ]
      }
    ]
  }
}

Key fields:

FieldWherePurpose
labeltab, groupDisplay name (any text, multi-word OK)
pathtab, pageURL segment — stable, kebab-case; changes here change URLs
filepageSource MDX file path (without .mdx)

The shorthand tab/group fields and string-form pages still work (a deprecation warning is logged). Prefer label + path and the object page form for new projects.

How pages map to files

A page declaration decouples three concerns:

index.mdx
quickstart.mdx
setup.mdx
DeclarationSource fileURLSidebar label
{ "file": "index" }index.mdx/documentationMDX frontmatter title
{ "file": "quickstart" }quickstart.mdx/documentation/quickstartMDX frontmatter title
{ "file": "guides/setup" }guides/setup.mdx/documentation/guides/setupMDX frontmatter title
{ "file": "api/overview", "path": "api", "label": "API" }api/overview.mdx/documentation/api"API"
  • filesource file (where cmdocs reads from)
  • pathURL path (tab-relative; defaults to file)
  • labelsidebar label (defaults to the MDX frontmatter title)

Use the full object form whenever you need to decouple. For simple cases { "file": "quickstart" } is enough.

Tabs

Tabs are the top-level grouping. Each tab contains its own sidebar with groups.

Prop

Type

Tab with icon and description

{
  "label": "API Reference",
  "path": "api",
  "description": "REST API endpoints",
  "icon": "Code",
  "groups": [
    {
      "label": "Endpoints",
      "pages": [
        { "file": "api/auth" },
        { "file": "api/users" }
      ]
    }
  ]
}

When tabs have an icon or description, they render as a rich dropdown in the sidebar.

Why set path explicitly?

If you only provide label, cmdocs falls back to slugify(label) for the URL — e.g. "API Reference" becomes /api-reference. This works, but it means renaming the label would change the URL, breaking external links.

Setting path: "api" locks the URL in place. You can freely rename the label to "REST API" or "API Docs" without breaking anything.

Tab mode

{
  "navigation": {
    "tabMode": "auto"
  }
}
ValueBehavior
"auto" (default)Tabs appear as a dropdown in the sidebar
"top"Tabs appear as a top bar above the sidebar

Single-tab behavior

When you only have one tab with no customization, the tab selector is hidden and groups appear directly in the sidebar. Give the tab an icon or description to show the dropdown.

To disable tabs entirely, set theme.sidebar.tabs to false.

Groups

Groups are labeled sections inside a tab. They affect sidebar display only — they do not add URL segments.

{
  "groups": [
    {
      "label": "Getting Started",
      "pages": [
        { "file": "index" },
        { "file": "quickstart" },
        { "file": "installation" }
      ]
    }
  ]
}

Prop

Type

Pages appear in the sidebar in the order they're listed.

Pages

Each page is an object:

Prop

Type

The index page

A page with file: "index" (or path: "index") maps to the tab root URL (/documentation rather than /documentation/index).

Nested pages

A file path containing / automatically creates a collapsible subfolder in the sidebar:

{
  "pages": [
    { "file": "guides/setup" },
    { "file": "guides/advanced" }
  ]
}

→ both land under a guides/ subfolder in the sidebar.

The navbar.links array supports four link types.

A simple text link. Use this for blog or marketing pages.

{
  "text": "Blog",
  "href": "/blog",
  "icon": "BookOpen",
  "active": "nested-url"
}

Prop

Type

2. Icon button

An icon-only button. Great for social links.

{
  "type": "icon",
  "text": "Discord",
  "href": "https://discord.gg/your-server",
  "icon": "MessageCircle",
  "label": "Join our Discord",
  "external": true
}

Prop

Type

3. Styled button

A primary button. Use sparingly for CTAs.

{
  "type": "button",
  "text": "Get Started",
  "href": "/documentation/quickstart",
  "icon": "ArrowRight"
}

Prop

Type

4. Dropdown menu

A menu containing multiple link items. Use this to group related links.

{
  "type": "menu",
  "text": "Resources",
  "icon": "MoreHorizontal",
  "items": [
    {
      "text": "Changelog",
      "href": "/changelog",
      "description": "See what's new"
    },
    {
      "text": "GitHub",
      "href": "https://github.com/owner/repo",
      "external": true
    }
  ]
}

Prop

Type

Each entry in items is a small object:

Prop

Type

Icons

Icons accept either:

  1. Lucide icon names — e.g. "BookOpen", "Rocket", "MessageCircle". See the full list at lucide.dev/icons.
  2. Emoji — e.g. "📖", "🚀", "💬".

Icons work in both tabs and navbar links.

Validating your navigation

Run cmdocs check to verify:

  • All page file fields point to existing MDX files
  • No duplicate tab path values
  • Internal links in MDX and navbar.links resolve to real pages
npx @cmdoss/cmdocs check

This catches typos before they hit production.

Full example

docs.json
{
  "navbar": {
    "title": "My Docs",
    "github": "https://github.com/owner/repo",
    "links": [
      {
        "text": "Dashboard",
        "href": "https://app.example.com",
        "icon": "LayoutDashboard",
        "external": true
      },
      {
        "type": "icon",
        "text": "Discord",
        "href": "https://discord.gg/invite",
        "icon": "MessageCircle",
        "label": "Join Discord",
        "external": true
      },
      {
        "type": "menu",
        "text": "Resources",
        "items": [
          { "text": "Blog", "href": "/blog", "description": "Latest articles" },
          { "text": "Changelog", "href": "/changelog", "description": "What's new" }
        ]
      }
    ]
  },
  "navigation": {
    "tabMode": "auto",
    "tabs": [
      {
        "label": "Documentation",
        "path": "documentation",
        "description": "Learn to use the platform",
        "icon": "BookOpen",
        "groups": [
          {
            "label": "Getting Started",
            "pages": [
              { "file": "index" },
              { "file": "quickstart" }
            ]
          },
          {
            "label": "Guides",
            "pages": [
              { "file": "guides/setup" },
              { "file": "guides/advanced" }
            ]
          }
        ]
      },
      {
        "label": "API Reference",
        "path": "api",
        "description": "REST API documentation",
        "icon": "Code",
        "groups": [
          {
            "label": "Endpoints",
            "pages": [
              { "file": "api/overview" },
              { "file": "api/authentication" }
            ]
          }
        ]
      }
    ]
  }
}

How is this guide?

On this page