|
| 1 | +--- |
| 2 | +title: Auto Sidebar |
| 3 | +--- |
| 4 | + |
| 5 | +# Auto Sidebar ((tag|VitePress plugin|blue)) |
| 6 | + |
| 7 | +[[readingTime]] |
| 8 | + |
| 9 | +[](https://github.com/binarynoir/vitepress-auto-sidebar) [](https://www.npmjs.com/package/@binarynoir/vitepress-auto-sidebar) [](https://github.com/binarynoir/vitepress-auto-sidebar/actions/workflows/ci.yml) [](https://github.com/binarynoir/vitepress-auto-sidebar/blob/main/LICENSE) |
| 10 | + |
| 11 | +`@binarynoir/vitepress-auto-sidebar` builds your sidebar by scanning your docs folder, so you stop hand-maintaining `themeConfig.sidebar`. Add a Markdown file and it appears in the sidebar, titled from its heading. |
| 12 | + |
| 13 | +## See it live |
| 14 | + |
| 15 | +The sidebar on the left is generated. The order and titles for this section come from one plain-text file, `plugins/.sidebar`: |
| 16 | + |
| 17 | +<<< @/plugins/.sidebar{txt} |
| 18 | + |
| 19 | +Reorder those lines, rebuild, and the sidebar follows. No config code changes. |
| 20 | + |
| 21 | +## Install |
| 22 | + |
| 23 | +```sh |
| 24 | +npm install --save-dev @binarynoir/vitepress-auto-sidebar |
| 25 | +``` |
| 26 | + |
| 27 | +## Use |
| 28 | + |
| 29 | +```ts |
| 30 | +// .vitepress/config.mts |
| 31 | +import { defineConfig } from 'vitepress'; |
| 32 | +import { generateSidebar } from '@binarynoir/vitepress-auto-sidebar'; |
| 33 | +import path from 'node:path'; |
| 34 | + |
| 35 | +export default defineConfig({ |
| 36 | + themeConfig: { |
| 37 | + sidebar: generateSidebar(path.resolve(import.meta.dirname, '..'), { |
| 38 | + maxDepth: 3, |
| 39 | + maxTitleLength: 50, |
| 40 | + }), |
| 41 | + }, |
| 42 | +}); |
| 43 | +``` |
| 44 | + |
| 45 | +Use `import.meta.dirname`, not `__dirname`: VitePress configs are ESM. |
| 46 | + |
| 47 | +Each top-level folder becomes its own sidebar, keyed by its URL prefix. A folder's landing page is its `index.md`, or its `README.md`. VitePress serves a `README.md` at `README.html`, so add [README Index](/plugins/readme-index/) to serve it at the folder's URL. A page title comes from, in order: the `.sidebar` file, the `title` frontmatter, the first `# Heading`, then the formatted filename. |
| 48 | + |
| 49 | +## `.sidebar` syntax |
| 50 | + |
| 51 | +| Line | Meaning | |
| 52 | +| -------------------- | ------------------------------------------------- | |
| 53 | +| `name` | Order this file or folder. | |
| 54 | +| `name:Custom Title` | Order it and override its title. | |
| 55 | +| `"https://…":Title` | Insert an external link in place. | |
| 56 | +| `...` | Everything not listed goes here, alphabetically. | |
| 57 | +| `-name` | Hide this entry. | |
| 58 | +| `.hide` / `.hideall` | Hide this folder's own link, or the whole folder. | |
| 59 | + |
| 60 | +Titles can be quoted, with single or double quotes, and may have a space after the colon: `name.md: "Title"` and `https://example.com: 'Title'` both work. A line that can't be parsed, such as a link with no title, logs a warning with its file and line number. |
| 61 | + |
| 62 | +Files need their `.md` extension in these lines. A `.exclude` file removes drafts by pattern, and a `sidebar.json` next to a folder is used verbatim when you want to hand-author one section. |
| 63 | + |
| 64 | +## Options |
| 65 | + |
| 66 | +| Option | Default | Description | |
| 67 | +| --------------------- | -------------- | --------------------------------------------------------------------- | |
| 68 | +| `maxDepth` | `3` | How many folder levels deep to recurse. | |
| 69 | +| `maxTitleLength` | `50` | Truncate generated titles beyond this length. | |
| 70 | +| `configFilenames` | `['.sidebar']` | Per-folder ordering file names. | |
| 71 | +| `excludeFilenames` | `['.exclude']` | Per-folder exclusion file names. | |
| 72 | +| `collapsed` | `false` | Initial collapsed state for section headers. | |
| 73 | +| `flattenSinglePage` | `true` | A folder with one page becomes a plain link instead of its own group. | |
| 74 | +| `titleReplacements` | `{}` | Words to replace in titles made from file and folder names. | |
| 75 | +| `stripTags` | `true` | Remove Markdown Tags syntax (`((tag\|draft))`) from titles. | |
| 76 | +| `transformTitle` | none | A function that gets every title before truncation. | |
| 77 | +| `groupTitleFromIndex` | `false` | Label a folder's group with its landing page's title. | |
| 78 | +| `verbose` | `false` | Log each folder as it is processed. | |
| 79 | + |
| 80 | +## Titles |
| 81 | + |
| 82 | +::: tip See it live |
| 83 | +The [Sidebar Titles Demo](./titles-demo/) folder, in the sidebar under **Auto Sidebar**, uses each option below on this site's real sidebar. |
| 84 | +::: |
| 85 | + |
| 86 | +A title made from a file or folder name is formatted: `getting-started.md` becomes "Getting Started". Only first letters are capitalised, so use `titleReplacements` for words with other casing. Keys match whole words, ignoring case: |
| 87 | + |
| 88 | +```ts |
| 89 | +generateSidebar(docsRoot, { |
| 90 | + titleReplacements: { github: 'GitHub', api: 'API', cicd: 'CI/CD' }, |
| 91 | +}); |
| 92 | +// github-actions/ → "GitHub Actions", cicd-setup.md → "CI/CD Setup" |
| 93 | +``` |
| 94 | + |
| 95 | +Titles an author wrote (a heading, `title` frontmatter, a `.sidebar` line) are never changed by `titleReplacements`. |
| 96 | + |
| 97 | +[Markdown Tags](/plugins/markdown-tags/) syntax is removed from every title, so `# Design ((tag|draft))` is listed as "Design". Set `stripTags: false` to keep it. |
| 98 | + |
| 99 | +For anything else, `transformTitle` gets every title before it is truncated, with where it came from: `'name'` (a file or folder name), `'page'` (frontmatter or the first heading) or `'config'` (a `.sidebar` line). Return the title to use, or `undefined` to keep it: |
| 100 | + |
| 101 | +```ts |
| 102 | +generateSidebar(docsRoot, { |
| 103 | + transformTitle: (title, { source }) => |
| 104 | + source === 'page' ? title.replace(/^Guide: /, '') : undefined, |
| 105 | +}); |
| 106 | +``` |
| 107 | + |
| 108 | +A folder's group label comes from, in order: its line in the parent's `.sidebar`, a `section-title` in its landing page's frontmatter, then the formatted folder name. With `groupTitleFromIndex: true`, the landing page's `title` or first `# Heading` is tried before the folder name. |
| 109 | + |
| 110 | +Pairs with [Auto Navbar](/plugins/auto-navbar): one folder structure drives both menus. |
| 111 | + |
| 112 | +[Source and full README on GitHub](https://github.com/binarynoir/vitepress-auto-sidebar) |
0 commit comments