Customization
Doctrine has two extension points: a stylesheet for appearance and a React component map for MDX. Both are project-level customization. See MDX components for the built-in component reference.
Add a stylesheet
Set styles to an existing file resolved from the project root:
import { defineConfig } from '@amamo/doctrine'
export default defineConfig({
styles: './docs/theme.css',
})Doctrine imports this file after its precompiled runtime CSS. Override only what the site needs:
:root {
--doctrine-accent: oklch(0.9 0.05 155);
--doctrine-accent-foreground: oklch(0.25 0.04 155);
--doctrine-separator: oklch(0.88 0.025 155);
--doctrine-sidebar: oklch(0.97 0.01 155);
--doctrine-ring: oklch(0.48 0.12 155);
--doctrine-radius: 0.9rem;
--doctrine-font-sans: Inter, sans-serif;
--doctrine-font-mono: 'JetBrains Mono', monospace;
--doctrine-content-width: 52rem;
}
[data-theme='dark'] {
--doctrine-background: oklch(0.14 0.02 250);
--doctrine-muted: oklch(0.21 0.02 250);
}Theme variables
| Variable | Controls |
|---|---|
--doctrine-background, --doctrine-foreground | Page background and primary text |
--doctrine-card, --doctrine-card-foreground | Raised card surfaces |
--doctrine-popover, --doctrine-popover-foreground | Menus, selects, and dialogs |
--doctrine-primary, --doctrine-primary-foreground | Primary actions and links |
--doctrine-secondary, --doctrine-secondary-foreground | Secondary surfaces |
--doctrine-muted, --doctrine-muted-foreground | Muted surfaces and secondary text |
--doctrine-accent, --doctrine-accent-foreground | Hovered and selected controls |
--doctrine-border, --doctrine-separator | Strong borders and subtle separators |
--doctrine-input, --doctrine-ring | Input boundaries and keyboard focus |
--doctrine-sidebar, --doctrine-sidebar-foreground | Navigation surface and text |
--doctrine-sidebar-accent, --doctrine-sidebar-accent-foreground | Navigation hover and selection |
--doctrine-code, --doctrine-code-foreground | Code block surface and text |
--doctrine-radius | Shared surface radius |
--doctrine-font-sans, --doctrine-font-display | UI, body, and heading font stacks |
--doctrine-font-mono | Code font stack |
--doctrine-content-width | Maximum article width |
--doctrine-sidebar-width, --doctrine-toc-width | Desktop navigation and TOC widths |
--doctrine-header-height | Sticky header height |
Put light values in :root and dark overrides in [data-theme='dark'].
Target stable layout slots
Use data-slot instead of depending on generated utility classes:
[data-slot='header'] {
box-shadow: 0 1px 0 color-mix(in oklab, var(--doctrine-ring) 25%, transparent);
}
[data-slot='brand'] {
color: var(--doctrine-accent);
}
[data-slot='content'] {
letter-spacing: 0.005em;
}The shell exposes header, header-inner, brand, navigation, sidebar, main, content,
page-actions-row, page-actions, page-actions-copy, page-actions-menu-trigger,
page-actions-menu, page-actions-markdown, page-actions-source, page-navigation, and footer.
Built-ins expose badge, callout, card, card-grid, code-block,
code-block-header, code-block-filename, code-block-language, code-block-copy, file-tree,
file-tree-list, file-tree-folder, file-tree-file, live-preview, live-preview-title,
live-preview-canvas, live-preview-code, live-preview-code-toggle, live-preview-source, step,
steps, table-scroll, tabs, tab-list, tab, and tab-panel.
Use Tailwind CSS
Doctrine's own interface is already compiled, so consumers do not need Tailwind. To use utilities inside MDX or custom components, declare Tailwind in the documentation project's root manifest:
pnpm add -D tailwindcssnpm install -D tailwindcssyarn add -D tailwindcssbun add -d tailwindcssThen opt the configured stylesheet into Tailwind and state what it should scan:
@import 'tailwindcss' source(none);
@source './';Doctrine checks the root package.json dependencies, dev dependencies, and optional dependencies.
When one declares tailwindcss, it enables @tailwindcss/vite in both commands. Without that
declaration, styles remains ordinary CSS.
Register or override components
Set components to a module with a default component map. Custom entries merge after the built-ins,
so equal names replace them:
import type { IDoctrineComponents } from '@amamo/doctrine'
import type { ComponentProps } from 'react'
import { Callout } from '@amamo/doctrine/components'
function BrandedCallout(props: ComponentProps<typeof Callout>) {
return <Callout className="branded-callout" {...props} />
}
export default { Callout: BrandedCallout } satisfies IDoctrineComponentsexport default defineConfig({
components: './docs/components.tsx',
})Define .branded-callout in styles, or use utilities after enabling Tailwind. Registering a
replaces Doctrine's base-aware link component, so the replacement must preserve any desired subpath
and external-link behavior.
Custom modules are executable in both Node.js SSR and the browser. Keep module initialization and rendering free of browser-only globals; use effects or event handlers for browser access.