Configuration

Every theme option lives under opts in your jsdoc.json (or, for TypeDoc, under the cleanJsdocTheme block in typedoc.json — see JSDoc vs TypeDoc just below). Setting up the rest of the build is covered in JSDoc Getting Started and TypeDoc Getting Started; this page documents the theme's own options.

Each option below shows the snippet for both tools in tabs — pick the one that matches your setup.

Unknown or misspelled options only warn by default (with a "did you mean?" hint) — the build continues. Set strict to turn those warnings into errors.

JSDoc vs TypeDoc

Every option on this page is the same for both tools — only where you put it differs. In JSDoc the theme options go under opts; in TypeDoc, under cleanJsdocTheme.

Theme options live under opts, alongside JSDoc's own options:

CODE
{
  source: { include: ["./src", "./README.md"] },
  plugins: ["plugins/markdown"],
  opts: {
    destination: "dist",
    recurse: true,
    template: "node_modules/clean-jsdoc-theme/dist",
    // ↓ theme options
    siteName: "My Library",
    sectionOrder: ["Getting Started", "Classes", "Modules"],
    clubSidebarItems: true,
    copyPage: { enabled: true, actions: ["copy", "view", "claude"] },
  },
}

The option names and values are identical — only the namespace changes: opts (JSDoc) vs cleanJsdocTheme (TypeDoc). One exception: the outputSourceFiles and sourceLinkToComment options sit under JSDoc's templates.default and are JSDoc-only.

Site & identity

siteName

The title shown in the header — plain text, or a logo image.

Expected: a string, or a logo set object. The logo set keys are all strings: light and dark are the logo URLs (or local paths) used in each theme, default is the fallback when a theme-specific one isn't given, and alt is the text shown if the image fails to load (and read by screen readers).

CODE
opts: { siteName: "My Library" }
// or a logo that swaps with the theme:
opts: {
  siteName: {
    light: "./assets/logo.svg",
    dark: "./assets/logo-dark.svg",
    alt: "My Library",
  },
}

Defaults to your package's name.

basePath

The site root path the renderer prefixes onto every internal link and asset — set it when the site is served under a sub-path rather than the domain root.

Expected: a string path. Defaults to "" (served at the root).

CODE
opts: { basePath: "/my-library" } // served at example.com/my-library/

siteUrl

Your site's public base URL. When set, the build emits a sitemap.xml at the output root — one entry per page (hidden source-viewer pages are excluded) — which you can submit to search engines or reference from robots.txt. Without it, no sitemap is generated.

Expected: an absolute http(s) URL. Only its origin is used for each page's URL; the deploy sub-path comes from basePath, so the two never double-count — a bare origin (https://example.com) and a full URL whose path equals your basePath (https://example.com/my-library) both produce the same, correct <loc> entries. Omit it (the default) for no sitemap.

CODE
opts: { siteUrl: "https://example.com", basePath: "/my-library" }
// → sitemap.xml with https://example.com/my-library/… URLs

favicon

A path to a favicon image. The bridge copies it to a content-hashed _assets/ asset and emits a <link rel="icon"> (with a type derived from the extension — .svgimage/svg+xml) into every page's <head>.

Expected: a string file path (.svg, .png, .ico, …), relative to the working dir. Omitted → no favicon link.

CODE
opts: { favicon: "./assets/logo-small.svg" }

An SVG favicon needs this option — browsers only auto-discover a root favicon.ico, never an SVG. An SVG icon can also adapt to light/dark with a @media (prefers-color-scheme: dark) block inside the SVG.

Content sources

readme

A Markdown file rendered as the site home page.

Expected: a path string. (A root docs/index.md overrides it — see docs.)

CODE
opts: { readme: "./README.md" }

docs

A directory of hand-written Markdown/HTML guides rendered as prose pages. The folder layout drives each page's URL and sidebar group; per-file YAML frontmatter (title, group, order, slug, hidden) overrides the defaults, and a root index.md becomes the home page.

Expected: a path string (a directory).

CODE
opts: { docs: "./docs" }

docGroups

The display order of the top-level doc groups in the sidebar.

Expected: an array of group-label strings.

CODE
opts: { docGroups: ["Getting Started", "Guides"] }

This very site is built with the docs and docGroups options — its guides are plain Markdown files grouped into the sidebar sections you're browsing right now. Want to build something similar? Browse the source: docs-site on GitHub.

defaultDocGroup

The group label a doc lands in when it declares none (no frontmatter group and no folder to humanize).

Expected: a single string.

CODE
opts: { defaultDocGroup: "Docs" }

tutorials

The JSDoc --tutorials directory. Each tutorial becomes a guide page, grouped under "Tutorials" in the sidebar.

Expected: a path string (a directory). Equivalent to JSDoc's -u flag.

CODE
opts: { tutorials: "./tutorials" }

sectionOrder

The order of all top-level sidebar sections — both your doc/category groups and the API kind labels (Classes, Modules, …). Listed labels come first in the given order; anything you omit is appended afterward.

Expected: an array of section-label strings.

CODE
opts: { sectionOrder: ["Getting Started", "Guides", "Classes", "Modules"] }

Under JSDoc, sectionOrder orders doc/tutorial groups and the API kind sections. Under TypeDoc it has no effect at all — that sidebar is a module/folder hierarchy with its own fixed ordering, and doc groups there are ordered by docGroups, not sectionOrder. See TypeDoc flavor.

clubSidebarItems

Collapse related entries (e.g. a module and its members) under a shared, collapsible parent, grouped by the path segment before the first /.

Expected: a boolean. Defaults to false.

clubSidebarItems has no effect on the TypeDoc API tree. See TypeDoc flavor.

CODE
opts: { clubSidebarItems: true }

Custom links pinned above the sidebar navigation.

Expected: an array of entries. Each is an object with title, a link (or href), an optional id, and an optional iconlucide:<name> or simpleicons:<name>, loaded from a CDN. Two optional fields control link presentation: target (the link target — an external link defaults to _blank) and class (extra CSS class(es) merged onto the rendered link).

CODE
opts: {
  menu: [
    { title: "Home", link: "/", icon: "lucide:home" },
    { title: "GitHub", link: "https://github.com/you/repo", icon: "simpleicons:github" },
    // Open in the same tab + tag with a custom class for styling via customCss:
    { title: "Changelog", link: "/changelog", target: "_self", class: "menu-changelog" },
  ],
}

The prev/next pager at the foot of each content page — two cards linking the adjacent pages in sidebar reading order. On by default; source-viewer pages never show it.

Expected: a boolean shorthand, or an object { enabled }. Defaults to true.

CODE
opts: { pageNav: false }
// or the object form: opts: { pageNav: { enabled: false } }

Appearance & assets

fonts

Override the type families.

Expected: an object with heading, body, and/or mono. heading and body are Google Font family names (loaded for you, existence-checked at build time); mono is a CSS font stack.

CODE
opts: {
  fonts: { heading: "Fraunces", body: "Spline Sans", mono: "Spline Sans Mono" },
}

colors and darkColors

Recolor the theme. colors is the light-mode palette (also the :root default); darkColors is the dark-mode palette, emitted under [data-theme="dark"]. Each merges per key over the built-in palette, so you can override just bg and keep every other default.

Expected: an object with any subset of these keys, each a CSS color string (the theme ships oklch, but any valid CSS color works):

KeyRole
bgPage background
bgMutedSubtle surfaces (code blocks, cards, sidebar)
fgBody text
fgMutedSecondary / muted text
accentLinks, focus rings, primary buttons
accentFgText/icon on an accent background
borderHairlines and dividers
codeHeaderBgCode-block header strip background
codeHeaderFgCode-block header label text
codeHighlightBgHighlighted code-line background (@playground / highlight=)

The three code* keys style the code-block chrome — the header strip (its background + the CODE/filename label) and the tint on a highlighted line. They default to a neutral #f7f7f7-equivalent in light and elevated greys in dark, so you only set them to match a custom palette.

CODE
opts: {
  colors: { bg: "oklch(0.99 0.01 95)", accent: "oklch(0.55 0.2 250)" },
  darkColors: { bg: "oklch(0.18 0.01 250)", accent: "oklch(0.7 0.16 250)" },
}

Unknown keys and non-string values are ignored. If you omit darkColors entirely, dark mode falls back to a sensible bg/fg swap of colors.

customCss and customJs

Inline CSS/JS injected into every page. Custom CSS loads after the theme stylesheet (so it overrides); custom JS runs last.

Expected: a string.

CODE
opts: { customCss: ".my-banner { color: rebeccapurple; }" }

customCssFile and customJsFile

Like the above, but read from a file on disk. The bridge copies each to a content-hashed asset and links it.

Expected: a path string.

CODE
opts: { customCssFile: "./extra.css", customJsFile: "./extra.js" }

hashCustomAssets

Whether custom-asset filenames are content-hashed (for cache-busting). Set false to keep stable, unhashed names.

Expected: a boolean. Defaults to true.

CODE
opts: { hashCustomAssets: false }

A custom site footer, rendered in place of the default footer on every page. Either an inline HTML string or { file: "./footer.html" } — the bridge reads the file at build time, so render() stays pure. It's trusted, author-controlled HTML (rendered verbatim, like v4's footer); style it with customCss / customCssFile, which load after the theme stylesheet so your selectors win.

Expected: a string, or { file }.

CODE
opts: { footer: "<div class='site-footer'>© 2026 My Library</div>" }
// or, for anything longer than a line:
opts: { footer: { file: "./footer.html" } }

meta

Site-wide custom <meta> tags. Pass an array of attribute objects — each object's key/value pairs become the attributes of one <meta> tag in <head> (name/content, property/content, http-equiv, charset, …). The theme emits charset/viewport/an auto description itself and de-dupes: an author entry sharing an identifying attribute (name / property / http-equiv / charset) replaces the theme's default rather than duplicating it (so your description wins). Values are escaped automatically; invalid attribute names are dropped. These are site-wide (no per-page meta yet).

Expected: an array of { [attr]: value } objects.

CODE
opts: {
  meta: [
    { name: "description", content: "Fast, typed docs for My Library" },
    { name: "keywords", content: "jsdoc, typescript, docs" },
    { property: "og:title", content: "My Library" },
    { property: "og:image", content: "https://example.com/card.png" },
    { name: "theme-color", content: "#0b0b0b" }
  ]
}

LLM & copy page

copyPage

The per-page "copy page" / "open in LLM" button (content pages only).

Expected: a boolean shorthand, or an object { enabled, actions } where actions is any of copy, view, claude, chatgpt, perplexity. On by default with all actions.

CODE
opts: { copyPage: { enabled: true, actions: ["copy", "view", "claude"] } }
// or simply: opts: { copyPage: false }

aiPrompt

A custom instruction prepended when a page is handed to an LLM via the open-in actions.

Expected: a string.

CODE
opts: { aiPrompt: "You are helping a developer use My Library. " }

Source files

These two are JSDoc-only. They live under templates.default (JSDoc's default-template namespace), not under opts or cleanJsdocTheme.

outputSourceFiles

Whether to generate the syntax-highlighted source-file viewer pages and the Source: file:line links on members.

Expected: a boolean. Defaults to true; set false to suppress both.

CODE
templates: { default: { outputSourceFiles: false } }

sourceLinkToComment

Where a Source: link lands: the symbol's declaration (default) or its documentation comment.

Expected: a boolean. Defaults to false (land on the declaration).

CODE
templates: { default: { sourceLinkToComment: true } }

How assets are handled

You don't configure this, but it's worth knowing how local files referenced from your docs, tutorials, README, and API doc comments are processed. Any image you link with a relative or root-relative path — ![diagram](./assets/flow.svg) — is copied into the site's _assets/ directory under a content-hashed name (e.g. _assets/flow.3de65053.svg) and the reference is rewritten to point at it. The hash is derived from the file's bytes, so an unchanged file keeps a stable, cacheable URL across builds and a changed one cache-busts automatically. External (https://…) and data: URLs are left untouched. (See Working with images for the full guide.)

.svg files get one extra step: their markup is inlined directly into the page rather than loaded through an <img>. That lets an SVG's own [data-theme="dark"] styles follow the in-page theme toggle — an <img>-loaded SVG can only see the operating system's color scheme, never your site's toggle.

Logos (siteName) and customCssFile / customJsFile ride the same content-hashed _assets/ pipeline.

JSDoc staticFiles

If you use JSDoc's standard templates.default.staticFiles.include to ship a folder of images (the convention where files land at the output root and you reference them by bare name, e.g. ![diagram](classes-io.png)), the theme honors it: those directories become fallback search roots, so a bare or root-relative reference resolves and flows through the same content-hashed _assets/ pipeline above — no need to rewrite your comments to relative paths. Any non-image files in those directories are still copied verbatim to the site root, matching JSDoc's behavior. (A file the image pipeline already served from _assets/ isn't copied to the root a second time.)

Localization

These two opt your site into a multi-language build — one static site per locale, with a header language switcher and hreflang alternates wired in. They declare the locales; the actual translation workflow (extracting catalogs, translating, and building each locale) runs through the clean-jsdoc CLI. The full walkthrough is in Localize your docs. A build with no locales is unaffected — it renders exactly as before.

Localized builds are JSDoc-only today. The TypeDoc bridge can extract catalogs but does not yet render the per-locale sites.

locales

The languages to build.

Expected: an array of { code, name } objects (the name is the switcher label), or bare locale-code strings. Codes are BCP-47-ish (en, pt-BR).

CODE
opts: {
  locales: [
    { code: "en", name: "English" },
    { code: "ja", name: "日本語" },
  ],
}

defaultLocale

The language rendered at the site root (every other locale lands under /<code>).

Expected: a locale code that appears in locales. Optional — defaults to the first entry.

CODE
opts: { defaultLocale: "en" }

Build

strict

Escalate option diagnostics (a bad font name, an unknown key) from warnings to hard build errors.

Expected: a boolean. Defaults to false.

CODE
opts: { strict: true }

progress

Toggle the build's progress output (the per-stage spinners).

Expected: a boolean. Defaults to true.

CODE
opts: { progress: false }