Skip to content

guides build a guides site

Ankit Kumar edited this page Jul 29, 2026 · 1 revision

Build a guides site

This is the prose-first workflow: you point the theme at a folder of hand-written Markdown (or HTML), and it becomes a full documentation site — sidebar, search, theme toggle, the works. No API reference required. It's exactly how the site you're reading is built.

Tip

This very site is the worked example. Its config is docs-site/jsdoc.json and its pages live in docs-site/docs/. Everything below is verified against the bridge in packages/setu/src/guide-view.ts.

The mental model

Point opts.docs at a directory. The theme walks it recursively, and each .md / .markdown / .html file becomes one page. The file's location in the folder drives two things automatically:

  • its URL slug — the relative path, slugified;
  • its sidebar group — the directory it sits in, humanized.

Per-file YAML frontmatter overrides either of those (and a few more). A root index.md becomes the home page. That's the whole system.

The directory walk happens in the bridge (collectDocs), which reads the files and hands them to setu; setu itself does no disk I/O. Only .md, .markdown, .html, and .htm files are picked up — node_modules, .git, and dotfiles/dot-dirs are skipped.

Set it up

Drop some Markdown into a directory. The layout is up to you:

docs/
  index.md            # → home page (slug "")
  getting-started.md  # → /getting-started, ungrouped
  guides/
    advanced.md       # → /guides/advanced, group "Guides"

Add docs to your config. Tutorials and the API are optional — a docs folder alone is a complete site.

{
  source: { include: ["./README.md"] },
  plugins: ["plugins/markdown"],
  opts: {
    destination: "dist",
    template: "node_modules/clean-jsdoc-theme/dist",
    docs: "./docs",
    docGroups: ["Getting Started", "Guides"],
    defaultDocGroup: "Docs",
  },
}
{
  entryPoints: ["src/index.ts"],
  plugin: ["@clean-jsdoc-theme/typedoc"],
  outputs: [{ name: "clean-jsdoc-theme", path: "dist" }],
  cleanJsdocTheme: {
    docs: "./docs",
    docGroups: ["Getting Started", "Guides"],
    defaultDocGroup: "Docs",
  },
}

Build as usual — see JSDoc Getting Started or TypeDoc Getting Started for the full toolchain setup.

npx jsdoc -c jsdoc.json

How a file becomes a page

For each file, setu derives the page metadata in deriveDocMeta. The rules, exactly as the code resolves them:

Field Derivation (first match wins)
slug frontmatter slug → slugified relative path (no prefix); index""
title frontmatter title → humanized basename of the path
group frontmatter group → humanized directory path → defaultDocGroup
order frontmatter order
hidden frontmatter hidden (default false)

Slugs come from the path

The slug is the relative path with the extension stripped, run through slugifyPath per segment: lowercased, runs of non-alphanumerics collapsed to -, joined with /. So guides/Advanced Setup.md/guides/advanced-setup. The slug carries no prefix — docs live at clean, top-level URLs (unlike tutorials, which are forced under tutorials/).

Groups come from the directory

A file's sidebar group defaults to its directory path, humanized per segment: guides/advanced.md lands in group Guides; guides/setup/install.md lands in the nested group Guides/Setup (a / in a group path nests it — see Structure your sidebar). A file at the docs root with no frontmatter group falls back to defaultDocGroup; if that's unset too, the page is ungrouped (it lands in the catch-all "Docs" section).

index.md → home page

A file whose path is exactly index (the docs-root index.md) becomes the home page: slug "", rendered at index.html. It overrides the readme home page when both exist.

Frontmatter overrides

Frontmatter is a leading --- block. The parser is deliberately small — simple key: value scalars (string / number / boolean), which is all the pipeline needs. The recognized keys:

---
title: Advanced Setup
group: Guides
order: 2
slug: guides/advanced
hidden: false
---

# Advanced Setup
...
  • title — the sidebar label and page <title>.
  • group — the sidebar group (overrides the directory). May be a /-path to nest.
  • order — the within-group sort key (ascending; unset sorts last, then alphabetical). See Structure your sidebar.
  • slug — a custom URL, replacing the path-derived one.
  • hidden — when true, the page is rendered but kept out of the sidebar (still reachable by direct link / cross-reference).

Note

The frontmatter parser is intentionally minimal: nested YAML, lists, and multi-line values are not supported — only flat key: value scalars. A malformed or unterminated block is treated as no frontmatter and left in the body. See parseFrontmatter in guide-view.ts.

Ordering the groups

Two levers, working at different scopes:

  • docGroups orders the top-level group sections in the sidebar (e.g. ["Getting Started", "Guides"]). Groups you don't list are appended after, alphabetically.
  • A page's frontmatter order positions it within its group.

This site sets both — see its jsdoc.json: docGroups (and sectionOrder) pin the group order, while each page's order frontmatter sequences the pages inside.

Important

docGroups only orders doc groups, and it appends them after the API kind sections. If you're mixing guides with an API reference and want full control over the entire sidebar — guides interleaved with Classes, Modules, etc. — reach for sectionOrder instead. See Combine guides + API.

Where to go next

Clone this wiki locally