Docusaurus DocsSitemap (Doc Titles)
Add a DocsSitemap component that reads sidebars.ts (or .js) and doc-titles.json to render an expand/collapse full-page navigation on the Docusaurus landing page.
Prerequisites
- •
gray-matternpm dependency - •Docusaurus site with
sidebars.ts(or.js) - •
routeBasePathset to/docs(sosrc/pages/index.tsxcan serve as landing page)
Step 1: Detect Docusaurus Root
Find the directory containing docusaurus.config.ts (or docusaurus.config.js). This is the Docusaurus root directory, referred to as {DOCUSAURUS_ROOT} throughout this skill. All file paths below are relative to this root.
Step 2: Create the doc-titles generation script
Create {DOCUSAURUS_ROOT}/scripts/generate-doc-titles.js:
#!/usr/bin/env node
const fs = require('fs');
const path = require('path');
const matter = require('gray-matter');
const DOCS_DIR = path.join(__dirname, '../docs');
const OUTPUT_FILE = path.join(__dirname, '../src/data/doc-titles.json');
The script recursively finds all .md/.mdx files in docs/, extracts title from frontmatter or first H1 heading, and outputs src/data/doc-titles.json as { "docId": "Title" }.
Step 3: Create the DocsSitemap component
Create {DOCUSAURUS_ROOT}/src/components/DocsSitemap/index.tsx:
import type { ReactNode } from 'react';
import useBaseUrl from '@docusaurus/useBaseUrl';
import sidebars from '@site/sidebars';
import docTitles from '@site/src/data/doc-titles.json';
function generateLabel(sidebarId: string): string {
const name = sidebarId.replace(/Sidebar$/, '');
// Add special cases as needed (e.g., inbox -> INBOX)
return name.charAt(0).toUpperCase() + name.slice(1);
}
Key features:
- •Reads sidebar entries from
sidebars.ts(or.js) - •For
autogeneratedsidebar items, resolves docs fromdoc-titles.jsonby matchingdirNameprefix - •Renders each sidebar as a
<details>/<summary>section (open by default) - •Animated chevron (
▶) rotates 90deg when open - •Hover effect on summary uses
--ifm-color-primary
For autogenerated sidebars, filter doc-titles.json entries by dirName/ prefix, excluding dirName/index, and render as links.
Step 4: Add to the landing page
Create {DOCUSAURUS_ROOT}/src/pages/index.tsx that imports and renders <DocsSitemap />. This requires routeBasePath in docusaurus.config.ts (or .js) to be /docs (not /).
Minimal landing page:
import Layout from '@theme/Layout';
import DocsSitemap from '@site/src/components/DocsSitemap';
export default function Home() {
return (
<Layout>
<main style={{ padding: '2rem', maxWidth: '900px', margin: '0 auto' }}>
<DocsSitemap />
</main>
</Layout>
);
}
Step 5: Update config
In docusaurus.config.ts (or .js):
- •Change
routeBasePath: '/'torouteBasePath: '/docs' - •Update search plugin's
docsRouteBasePathto/docs
Delete {DOCUSAURUS_ROOT}/docs/intro.md if it has slug: / (it conflicts with the new landing page).
Update any absolute doc links from /category/page to /docs/category/page.
Step 6: Wire up scripts and gitignore
In package.json, add:
"generate:doc-titles": "node scripts/generate-doc-titles.js"
Ensure generate script calls it, and start/build call generate first.
Add to .gitignore:
src/data/doc-titles.json
Step 7: Verify
Run pnpm run generate then pnpm run build. Verify the landing page shows expandable sidebar sections with all doc links.