Style and Layout
Trellis Docs includes custom theme components and a design token system that give you full control over your site's look and feel.
Theme components
Trellis Docs uses fully custom theme components. This gives complete control over every aspect of rendering — from where the last-updated date appears to what icons admonitions use.
Directory structure
components/docs/
├── mdx/
│ ├── index.tsx # MDX component registry
│ ├── callout.tsx # Admonitions (note, tip, info, caution, danger) with custom SVG icons
│ ├── code-block.tsx # Shiki syntax highlighting (server component)
│ ├── code-block-client.tsx # Copy button + word wrap toggle (client component)
│ ├── heading.tsx # Heading anchors with copy-to-clipboard
│ ├── tabs.tsx # Pill-style tabs with URL sync
│ ├── image-lightbox.tsx # Click-to-zoom image modal
│ └── mermaid.tsx # Mermaid diagram renderer with pan/zoom
├── search/
│ └── search-dialog.tsx # Cmd+K search modal (Fuse.js)
├── navbar.tsx # Top navbar + mobile sidebar drawer
├── sidebar.tsx # Desktop sidebar with collapsible categories
├── breadcrumbs.tsx # Breadcrumb navigation
├── toc.tsx # Table of contents (right sidebar)
└── footer.tsx # Site footerModifying theme components
To customize a component, edit it directly in components/docs/.
Before making changes, read the existing component code to understand what it does.
Since these are custom components, they are maintained within the Trellis project. When upgrading Next.js, check for any breaking changes that might affect theme components.
Last-updated placement
In many documentation frameworks, the last-updated date and "Edit this page" link appear at the bottom of the page, in the footer area. Trellis Docs moves them to the top, directly below the page title.
Why top placement?
Readers want to know immediately whether the content they're reading is current. Placing the date at the top gives instant context about freshness — no scrolling required. This is especially important for documentation that changes frequently, like API references or configuration guides.
Configuration
The date and author are set per-page via frontmatter:
---
last_update:
date: 02/20/2026
author: Your Name
---The author field is useful as a subject matter expert reference for contributors. To control whether the author name is displayed on the page, toggle showAuthor in config/site.ts:
lastUpdated: {
showAuthor: false, // true to display the author next to the date
},When showAuthor is false (the default), only the date renders. The author remains in the frontmatter for contributor reference.
Design tokens
Trellis Docs uses a design token system that converts a single JSON file into CSS custom properties. This gives you a centralized place to define your brand colors, spacing, typography, and other design values.
How it works
design-tokens.json → build-tokens.js → app/tokens.css → globals.cssdesign-tokens.jsondefines tokens as nested objects withvalueandtypepropertiesscripts/build-tokens.jsreads the JSON and generates a:root {}CSS blockapp/tokens.cssis the generated output (do not edit manually)app/globals.cssmaps token variables to CSS variables
The script runs automatically before npm run dev and npm run build (via the prebuild and predev npm scripts).
Token file structure
{
"brand": {
"primary-600": {
"value": "#7c3aed",
"type": "color"
}
},
"accent": {
"teal-400": {
"value": "#2dd4bf",
"type": "color"
}
},
"spacing": {
"spacing-16": {
"value": "16px",
"type": "spacing"
}
}
}Each token has:
value— the actual CSS valuetype— a descriptor (used for documentation; not consumed by the build script)
Generated CSS
The build script converts nested keys into CSS custom property names using -- prefix and - separators:
:root {
--brand-primary-600-value: #7c3aed;
--accent-teal-400-value: #2dd4bf;
--spacing-spacing-16-value: 16px;
}Token categories
The default design-tokens.json includes these categories:
| Category | Tokens | Description |
|---|---|---|
neutral | white, slate-50 through slate-900 | Background and text colors |
brand | primary-50 through primary-900 | Primary brand color scale (violet) |
accent | teal-200 through teal-600 | Accent color scale (teal) |
utility | green-20/100, red-20/100, yellow-20/100 | Status/feedback colors |
spacing | spacing-8 through spacing-120 | Spacing values in pixels |
border-radius | border-radius-4/8/30/900 | Border radius values |
border-width | border-width-1/2/none | Border width values |
typography | fontFamily | Font family stack |
Using tokens in CSS
Reference generated tokens in globals.css or any CSS module:
.my-component {
color: var(--brand-primary-600-value);
background: var(--neutral-slate-50-value);
padding: var(--spacing-spacing-16-value);
border-radius: var(--border-radius-border-radius-8-value);
}Mapping to theme variables
globals.css maps tokens to theme CSS variables so the entire theme responds to token changes:
:root {
--ifm-color-primary: var(--brand-primary-600-value);
--ifm-color-primary-dark: var(--brand-primary-700-value);
--ifm-color-primary-light: var(--brand-primary-500-value);
--ifm-font-family-base: var(--typography-font-family-value);
}Customizing design tokens
Changing brand colors
Open design-tokens.json and update the brand section. The default uses a navy blue scale:
{
"brand": {
"primary-50": { "value": "#f0f5fa", "type": "color" },
"primary-100": { "value": "#dce8f2", "type": "color" },
"primary-200": { "value": "#b3cde0", "type": "color" },
"primary-300": { "value": "#8bb3cf", "type": "color" },
"primary-400": { "value": "#7ba4c4", "type": "color" },
"primary-500": { "value": "#4a7da8", "type": "color" },
"primary-600": { "value": "#2a5a82", "type": "color" },
"primary-700": { "value": "#1a3b5c", "type": "color" },
"primary-800": { "value": "#122a43", "type": "color" },
"primary-900": { "value": "#0b1c2e", "type": "color" }
}
}Replace the hex values with your brand's color scale. Use a tool like Tailwind CSS Colors or Coolors to generate a consistent scale.
After editing, regenerate the CSS:
npm run build-tokensOr restart the dev server — it runs build-tokens automatically:
npm run devChanging accent colors
The accent section controls secondary colors used for interactive elements like links and highlights in dark mode:
{
"accent": {
"olive-200": { "value": "#dde896", "type": "color" },
"olive-300": { "value": "#c8d96e", "type": "color" },
"olive-400": { "value": "#b4ca4a", "type": "color" },
"olive-500": { "value": "#a2b53a", "type": "color" },
"olive-600": { "value": "#8a9a2f", "type": "color" }
}
}When choosing accent colors, ensure sufficient contrast against both light and dark backgrounds. The 400 shade is used most often.
Adding tokens
Add categories or tokens by extending the JSON structure:
{
"brand": {
"primary-600": { "value": "#2a5a82", "type": "color" },
"secondary-600": { "value": "#2563eb", "type": "color" }
}
}The build script generates:
--color-brand-secondary-600: #2563eb;You can then use it in app/globals.css or any component:
.my-element {
color: var(--color-brand-secondary-600);
}Changing typography
Update the font family in the typography section:
{
"typography": {
"fontFamily": {
"name": "font-family",
"value": "'Inter', 'Segoe UI', system-ui, sans-serif"
}
}
}If using a web font, add the import in app/globals.css:
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap');Replacing the logo
Trellis ships with built-in SVG logo components. To use your own logo:
Option A: Image files (simplest)
-
Place your logo images in
public/img/:- Navbar logo — small mark, ~32px tall (e.g.
my-logo-small.svg) - Hero logo — larger version for the landing page (e.g.
my-logo-hero.svg)
- Navbar logo — small mark, ~32px tall (e.g.
-
Update
config/site.ts:
logo: {
navbar: '/img/my-logo-small.svg',
hero: '/img/my-logo-hero.svg',
alt: 'My Company Logo',
useBuiltIn: false, // Use image files instead of built-in SVG components
},Option B: React components (advanced)
For full control, replace the built-in components in components/brand/trellis-logo.tsx with your own SVG React components. The built-in components are:
| Component | Used in | Description |
|---|---|---|
TrellisIcon | Navbar | Small circular mark |
TrellisStacked | Landing page hero | Icon + text stacked vertically |
TrellisHorizontal | — | Icon + text side by side |
TrellisWordmark | — | Text only, no icon |
TrellisFavicon | — | Simplified 32x32 mark |
Keep useBuiltIn: true in config/site.ts to use these components.
Logo text elements use fill="currentColor" so they automatically adapt to light and dark mode. Follow this pattern for your own SVG components.
Full rebranding checklist
- Colors — Update
brandandaccentsections indesign-tokens.json. - Typography — Update
typography.fontFamily(add web font import if needed). - Logo — Replace images in
public/img/or update components incomponents/brand/. - Config — Update
title,tagline,url,repoUrl, andlogoinconfig/site.ts. - Navigation — Update links in
config/navigation.tsand copyright infooterConfig. - Regenerate — Run
npm run build-tokens. - Verify — Run
npm run buildand check for errors, thennpm run devfor visual review.
Token naming conventions
Follow these conventions for consistency:
- Colors:
{category}-{shade}→primary-600,olive-400 - Spacing:
spacing-{pixels}→spacing-16,spacing-24 - Border radius:
border-radius-{pixels}→border-radius-8 - Border width:
border-width-{pixels}→border-width-1
The build script converts these to CSS variables by joining the full path with hyphens: --color-brand-primary-600, --spacing-spacing-16.