--- name: fumadocs-page-tree description: | Structure a Fumadocs page tree — content folders, meta.json, slugs, sidebar. Use when adding, moving, or reordering doc pages under a content directory, editing a meta.json, creating sidebar sections (folder groups, clickable section headers), or controlling sidebar expansion. --- # Fumadocs page tree Page URLs and the sidebar both derive from the content directory layout plus per-folder `meta.json`. This file covers the load-bearing rules and the traps; verify anything beyond it against the local checkout `~/repo/fumadocs` — conventions in `apps/docs/content/docs/headless/page-conventions.mdx`, ground truth in `packages/core/src/source/plugins/slugs.ts` (slugs) and `packages/core/src/source/page-tree/builder.ts` (tree). In this repo `fumadocs-ui` is aliased to `@fumadocs/base-ui` (`packages/base-ui` in the checkout); the layout API is identical. ## Slugs - `dir/page.mdx` → `/docs/dir/page`; `dir/index.mdx` → `/docs/dir`. - A parenthesized folder `(name)/` is **slug-transparent**: stripped from slugs, so children keep parent-level URLs. Use it for sidebar-only grouping. - Each URL may appear once in the entire tree — duplicates are an error by design. ## meta.json Folder fields: `title`, `icon`, `description`, `defaultOpen`, `collapsible`, `root`, `pages`, `pagesIndex`. `pages` entry syntax: | Entry | Meaning | | --------------- | --------------------------------------------------- | | `"page"` / `"dir"` | path to a page or folder (relative paths allowed) | | `"(group)"` | folder group, referenced by its literal name | | `"---Label---"` | separator (icon form: `---[Icon]Label---`) | | `"[Text](url)"` | link; `external:[Text](url)` marks it external | | `"..."` / `"z...a"` | remaining items, alphabetical / reversed | | `"...dir"` | inline a folder's items into this level | | `"!item"` | exclude from `...` | - `pages` is **exhaustive**: once present, unlisted items are dropped unless `...` appears. Use an explicit array to pin sidebar order. - `"root": true` makes a root folder: rendered as layout tabs, and only the active root's items are visible. ## Clickable section header (folder index) A folder containing an `index` page attaches it as the folder's own link: the header becomes clickable and the index leaves the child list. - Keep `pages` free of `"index"` — the index auto-resolves. Listing it demotes the folder to a plain label with the index as an ordinary child row (`builder.ts` deletes `node.index` when `pages` claims it). - `pagesIndex` overrides which page (or `[Text](url)` link) serves as the folder's index. - Slug-transparent group + index composes into "section header linking to a parent-level URL": `(intro)/index.mdx` gives a clickable **Intro** header → `/docs`, with siblings like `(intro)/install.mdx` → `/docs/install`. ## Sidebar expansion - `` — a folder starts open when `defaultOpenLevel >= depth` (top-level folders are depth 1) or when it contains the active page. Default `0`: everything starts collapsed. - Per-folder overrides in its `meta.json`: `defaultOpen: true` opens one folder; `collapsible: false` pins it open with no toggle.