# Creating Your Own Theme
URL: /docs/themes/creating-themes
LLM index: /llms.txt
Description: Step-by-step guide to building, publishing, and sharing custom themes

import { WebsiteThemePrompt } from "@/components/website-theme-prompt";

# Creating Your Own Theme

Use this page when the user asks about this topic: Step-by-step guide to building, publishing, and sharing custom themes.
Keep answers grounded in the exact options, routes, commands, and examples documented here.
If the request moves beyond this page, point to the closest related docs instead of inventing config.

Everything starts with `createTheme()`. No CSS required — just a config object.

## Quick Start

```ts
import { createTheme } from "@farming-labs/docs";

export const myTheme = createTheme({
  name: "my-theme",
  ui: {
    colors: {
      primary: "#e11d48",
      background: "#09090b",
      muted: "#71717a",
      border: "#27272a",
    },
  },
});
```

```tsx title="docs.config.tsx"
import { defineDocs } from "@farming-labs/docs";
import { myTheme } from "./my-theme";

export default defineDocs({
  entry: "docs",
  theme: myTheme(),
});
```

That's it. Users can override any of your defaults:

```tsx title="quick-start.tsx"
theme: myTheme({
  ui: { colors: { primary: "#3b82f6" } },
});
```

---

## Prompt: Match an Existing Website

Use this prompt when you already have a product or marketing website and want the docs to feel like
the same brand.

<WebsiteThemePrompt>
Create or update an `@farming-labs/docs` theme so the documentation feels visually consistent with
my existing website.

Inputs:
- Website URL: [WEBSITE_URL]
- Docs entry folder: [DOCS_ENTRY]
- Framework: [FRAMEWORK]
- Brandfetch brand context:
[BRAND_CONTEXT]

Use the @farming-labs/docs website as implementation context before coding:
- Framework docs: https://docs.farming-labs.dev
- Theme guide: https://docs.farming-labs.dev/docs/themes/creating-themes
- Components guide: https://docs.farming-labs.dev/docs/customization/components
- CLI guide: https://docs.farming-labs.dev/docs/cli

Use the Brandfetch brand context as brand hints, then inspect the existing website directly and
extract its design system:
- brand colors, accent colors, background colors, border colors, and focus states
- typography, font families, heading scale, body size, line height, and code font
- border radius, shadows, dividers, spacing rhythm, and card/button treatment
- navigation style, sidebar/header feel, search affordance, tabs, callouts, code blocks, and tables
- light/dark mode behavior if the site supports it

Then implement the docs theme:
- choose the closest built-in `@farming-labs/docs` theme as the base, or create a custom theme with
  `createTheme()` / `extendTheme()`
- update `docs.config.ts[x]` to use the theme
- add or update the theme CSS import in the app's global stylesheet
- add CSS overrides only where the config tokens are not enough
- keep the docs interface readable, scannable, and documentation-first; do not copy marketing hero
  sections into docs pages
- preserve agent-ready docs features such as `.md` routes, `llms.txt`, `AGENTS.md`, `skill.md`, sitemap,
  `robots.txt`, MCP, JSON-LD, and markdown alternate links

Verification:
- run the docs dev server
- check desktop and mobile layouts
- confirm text does not overflow buttons, cards, sidebars, or code blocks
- confirm search, sidebar navigation, code blocks, callouts, tabs, and page actions still work
- list the files changed and explain which website design tokens were mapped into the docs theme
</WebsiteThemePrompt>

The copy button asks for the website URL, fetches Brandfetch brand details, defaults the docs entry
folder to `docs`, defaults the framework to `Next.js`, and fills those placeholders before copying.
If the website uses a very expressive landing page, ask for a docs interpretation of the brand
instead of a literal copy. Documentation should feel connected to the product while staying calmer,
denser, and easier to scan.

---

## Config Options Reference

Here's everything you can configure in `createTheme()`.

### `name`

Unique identifier for your theme. Used for debugging and CSS scoping.

```ts 
name: "my-theme";
```

### `ui.colors`

Color tokens mapped to `--color-fd-*` CSS variables at runtime. Any valid CSS color value works (hex, rgb, hsl, oklch).

```ts title="ui-colors.ts"
colors: {
  primary: "#e11d48",               // brand color — links, buttons, active states
  primaryForeground: "#ffffff",      // text on primary backgrounds
  background: "#09090b",            // page background
  foreground: "#fafafa",            // default text color
  muted: "#71717a",                 // muted backgrounds (badges, tags)
  mutedForeground: "#a1a1aa",       // secondary text, descriptions
  border: "#27272a",               // borders and dividers
  card: "#18181b",                 // card / callout backgrounds
  cardForeground: "#fafafa",        // text inside cards
  accent: "#27272a",               // hover backgrounds
  accentForeground: "#fafafa",      // text on hover backgrounds
  secondary: "#27272a",            // secondary button backgrounds
  secondaryForeground: "#fafafa",   // text on secondary
  popover: "#18181b",              // dropdown / dialog backgrounds
  popoverForeground: "#fafafa",     // text inside popovers
  ring: "#e11d48",                 // focus ring on interactive elements
}
```

You only need to set the ones you want to change — the rest are inherited from the base preset.

### `ui.typography`

Font families, heading sizes, weights, line heights, and letter spacing.

```ts title="ui-typography.ts"
typography: {
  font: {
    // Font families
    style: {
      sans: "Inter, system-ui, sans-serif",
      mono: "JetBrains Mono, monospace",
    },
    // Heading styles
    h1: { size: "2.25rem", weight: 700, lineHeight: "1.2", letterSpacing: "-0.02em" },
    h2: { size: "1.5rem", weight: 600, lineHeight: "1.3", letterSpacing: "-0.01em" },
    h3: { size: "1.25rem", weight: 600, lineHeight: "1.4" },
    h4: { size: "1.125rem", weight: 600, lineHeight: "1.4" },
    // Body and small text
    body: { size: "1rem", weight: 400, lineHeight: "1.75" },
    small: { size: "0.875rem", weight: 400, lineHeight: "1.5" },
  },
}
```

Each heading/text style accepts these properties:

| Property        | Type               | Example               |
| --------------- | ------------------ | --------------------- |
| `size`          | `string`           | `"2.25rem"`, `"36px"` |
| `weight`        | `number \| string` | `700`, `"bold"`       |
| `lineHeight`    | `string`           | `"1.2"`, `"28px"`     |
| `letterSpacing` | `string`           | `"-0.02em"`           |

**Tip:** Use CSS variables for fonts so users can load them with `next/font`:

```ts title="example.ts"
style: {
  sans: "var(--font-geist-sans, system-ui, sans-serif)",
  mono: "var(--font-geist-mono, ui-monospace, monospace)",
}
```

### `ui.radius`

Global border radius. Maps to CSS `--radius`.

```ts title="ui-radius.ts"
radius: "0.5rem"; // rounded
radius: "0px"; // sharp corners
radius: "0.75rem"; // more rounded
```

### `ui.layout`

Content area dimensions and structural options.

```ts title="ui-layout.ts"
layout: {
  contentWidth: 768,       // max width of docs content (px)
  sidebarWidth: 280,       // sidebar width (px)
  tocWidth: 220,           // table of contents width (px)
  toc: {
    enabled: true,         // show table of contents
    depth: 3,              // heading depth (2 = h2 only, 3 = h2 + h3)
  },
  header: {
    height: 64,            // header height (px)
    sticky: true,          // stick header on scroll
  },
}
```

### `ui.codeBlock`

Code block rendering options.

```ts title="ui-codeblock.ts"
codeBlock: {
  showLineNumbers: false,  // show line numbers
  showCopyButton: true,    // show copy button
  theme: "github-dark",    // shiki syntax theme
  darkTheme: "github-dark", // dark mode shiki theme (for dual-theme)
}
```

### `ui.sidebar`

Sidebar visual style.

```ts title="ui-sidebar.ts"
sidebar: {
  style: "default",        // "default" | "bordered" | "floating"
  background: undefined,   // override sidebar background
  borderColor: undefined,  // override sidebar border color
}
```

| Style        | Description                                             |
| ------------ | ------------------------------------------------------- |
| `"default"`  | Standard fumadocs sidebar                               |
| `"bordered"` | Visible bordered sections (inspired by better-auth.com) |
| `"floating"` | Floating card sidebar with subtle shadow                |

### `ui.card`

Card styling.

```ts title="ui-card.ts"
card: {
  bordered: true,          // show card borders
  background: undefined,   // override card background
}
```

### `ui.components`

Default props for built-in MDX components.

```ts title="ui-components.ts"
components: {
  Callout: { variant: "outline" },   // or "soft"
  CodeBlock: { showCopyButton: true },
  Tabs: { style: "default" },
  HoverLink: {
    linkLabel: "Open page",
    showIndicator: false,
    align: "start",
  },
}
```

`ui.components` changes the default props for built-in MDX components. For example, `HoverLink`
can keep the built-in popover UI while changing its CTA label, indicator, or alignment across your
docs. If you want to replace the component completely, use `components.HoverLink` in
`docs.config.tsx` instead.

---

## Full Example

Here's a complete theme with every option:

```ts
import { createTheme } from "@farming-labs/docs";

export const MyThemeDefaults = {
  colors: {
    primary: "#8b5cf6",
    background: "#0f0f11",
    foreground: "#e4e4e7",
    muted: "#1e1e2e",
    mutedForeground: "#71717a",
    border: "#27272a",
    card: "#18181b",
    accent: "#27272a",
    ring: "#8b5cf6",
  },
  typography: {
    font: {
      style: {
        sans: "Inter, system-ui, sans-serif",
        mono: "Fira Code, monospace",
      },
      h1: { size: "2.5rem", weight: 800, letterSpacing: "-0.03em" },
      h2: { size: "1.75rem", weight: 700, letterSpacing: "-0.02em" },
      h3: { size: "1.25rem", weight: 600 },
      body: { size: "1rem", lineHeight: "1.8" },
    },
  },
  radius: "0.5rem",
  layout: {
    contentWidth: 800,
    sidebarWidth: 260,
    toc: { enabled: true, depth: 3 },
    header: { height: 56, sticky: true },
  },
  sidebar: { style: "bordered" as const },
  codeBlock: { showCopyButton: true, theme: "github-dark" },
  components: {
    Callout: { variant: "outline" },
    HoverLink: { linkLabel: "Open page", showIndicator: false },
  },
};

export const myTheme = createTheme({
  name: "my-theme",
  ui: MyThemeDefaults,
});

// Export defaults so others can extend your theme
export { MyThemeDefaults };
```

---

## Extending an Existing Theme

Don't want to start from scratch? Use `extendTheme()` to build on top of a built-in preset:

```ts
import { extendTheme } from "@farming-labs/docs";
import { fumadocs } from "@farming-labs/theme";

export const myTheme = extendTheme(fumadocs(), {
  name: "my-fumadocs-variant",
  ui: {
    colors: { primary: "#22c55e", background: "#0c0c0c" },
    sidebar: { style: "bordered" },
  },
});
```

Works with any built-in theme:

```ts title="extending-an-existing-theme.ts"
import { darksharp } from "@farming-labs/theme/darksharp";

export const myDark = extendTheme(darksharp(), {
  name: "my-dark-variant",
  ui: {
    colors: { primary: "#f97316" },
    radius: "0.75rem",
  },
});
```

> `extendTheme()` returns a `DocsTheme` directly (not a factory). Use `createTheme()` when building a reusable preset.

---

## Cherry-Picking from Built-in Themes

Each built-in theme exports its defaults object:

```ts title="cherry-picking-from-built-in-themes.ts"
import { DefaultUIDefaults } from "@farming-labs/theme/default";
import { DarksharpUIDefaults } from "@farming-labs/theme/darksharp";
import { PixelBorderUIDefaults } from "@farming-labs/theme/pixel-border";
import { createTheme } from "@farming-labs/docs";

export const myTheme = createTheme({
  name: "my-hybrid-theme",
  ui: {
    colors: PixelBorderUIDefaults.colors,
    typography: DefaultUIDefaults.typography,
    layout: DarksharpUIDefaults.layout,
    sidebar: { style: "floating" },
  },
});
```

---

## Publishing as an npm Package

```text
my-fumadocs-theme/
  src/
    index.ts       ← createTheme() + exported defaults
    theme.css      ← CSS overrides (optional)
  package.json
```

```json title="package.json"
{
  "name": "my-fumadocs-theme",
  "version": "1.0.0",
  "type": "module",
  "exports": {
    ".": { "import": "./dist/index.mjs", "types": "./dist/index.d.mts" },
    "./css": "./src/theme.css"
  },
  "peerDependencies": {
    "@farming-labs/docs": ">=0.0.1"
  }
}
```

Users install and use:

```bash title="terminal"
npm install my-fumadocs-theme
```

```tsx title="docs.config.tsx"
import { myTheme } from "my-fumadocs-theme";
export default defineDocs({ entry: "docs", theme: myTheme() });
```

```css title="app/global.css"
@import "tailwindcss";
@import "my-fumadocs-theme/css";
```

---

## Advanced: CSS Customization

> The config options above cover most use cases. But if you need **pixel-level control** over specific components — like how the sidebar active state looks, code block borders, table styling, or callout appearance — you can write a CSS file alongside your theme.

### How it Works

Every theme can ship a CSS file that sits on top of the config. The CSS file:

1. Imports a **color preset** (which includes fumadocs-ui core styles)
2. Overrides CSS variables for light (`:root`) and dark (`.dark`) modes
3. Targets specific component selectors to customize their appearance

### Starting Point

```css title="my-theme/theme.css"
/* Pick a color preset as your base */
@import "@farming-labs/theme/presets/black";
/* Or: @import "@farming-labs/theme/presets/neutral"; */

/* Override CSS variables */
.dark {
  --color-fd-primary: #22d3ee;
  --color-fd-background: #0a0a0f;
  --color-fd-border: #1e293b;
  --radius: 0.5rem;
}
```

Two presets are available:

| Preset  | Import                                | Best for           |
| ------- | ------------------------------------- | ------------------ |
| Neutral | `@farming-labs/theme/presets/neutral` | Light-first themes |
| Black   | `@farming-labs/theme/presets/black`   | Dark-first themes  |

### Component CSS Selectors

Here are all the selectors you can target to style individual components:

#### Sidebar

```css title="radius.css"
/* Container */
.dark aside#nd-sidebar {
  background: hsl(0 0% 2%);
  border-color: hsl(0 0% 12%);
}

/* All sidebar links */
.dark aside a[data-active] {
  font-size: 0.875rem;
  border-radius: 0.2rem;
  color: hsl(0 0% 50%);
}

/* Active link (current page) */
.dark aside a[data-active="true"] {
  background: hsl(0 0% 14%);
  color: var(--color-fd-primary);
  font-weight: 600;
}

/* Hover on inactive links */
.dark aside a[data-active="false"]:hover {
  color: hsl(0 0% 90%);
}

/* Folder toggle buttons */
.dark aside button.text-fd-muted-foreground {
  color: hsl(0 0% 90%);
  font-weight: 500;
}

/* Child links inside folders */
.dark aside div.overflow-hidden[data-state] a[data-active] {
  font-size: 0.785rem;
  padding-left: 2rem;
}

/* Search button */
.dark aside button[class*="bg-fd-secondary"] {
  background: transparent;
  border-top: 1px solid hsl(0 0% 12%);
  border-bottom: 1px solid hsl(0 0% 12%);
}

/* Active link indicator bar */
.dark aside a[data-active="true"]::before {
  background-color: var(--color-fd-primary);
  width: 2px;
}
```

#### Code Blocks

```css title="example.css"
/* Container */
figure.shiki {
  border: 1px solid var(--color-fd-border);
  border-radius: 0.5rem;
}

/* Title bar */
figure.shiki > div:first-child {
  border-radius: 0.5rem 0.5rem 0 0;
}

/* Copy button */
figure.shiki button {
  border-radius: 0.25rem;
}
```

#### Inline Code

```css title="inline-code.css"
code:not(pre code) {
  border-radius: 0.25rem;
}

.dark code:not(pre code) {
  background: hsl(0 0% 10%);
  border: 1px solid hsl(0 0% 16%);
  color: hsl(0 0% 85%);
}
```

#### Tables

```css title="tables.css"
.dark table {
  border: 1px solid hsl(0 0% 15%);
}

.dark th {
  background: hsl(0 0% 6%);
  color: hsl(0 0% 80%);
}

.dark td {
  border-color: hsl(0 0% 12%);
}
```

#### Callouts

```css title="callouts.css"
[class*="bg-fd-card"],
[role="alert"] {
  border-radius: 0.5rem;
}

.dark [class*="bg-fd-card"] {
  border-color: hsl(0 0% 14%);
}
```

#### Tabs

```css title="tabs.css"
.dark [role="tablist"] {
  border-radius: 0.5rem;
}

.dark [role="tab"] {
  border-radius: 0.25rem;
}
```

#### Prev/Next Navigation Cards

```css title="prev-next-navigation-cards.css"
.dark article a[class*="border"] {
  border-color: hsl(0 0% 15%);
  border-radius: 0.5rem;
}

.dark article a[class*="border"]:hover {
  background: hsl(0 0% 6%);
}
```

#### Search Dialog

```css title="search-dialog.css"
[role="dialog"] {
  border-radius: 0.5rem;
}
```

#### Breadcrumb

```css title="breadcrumb.css"
.fd-breadcrumb {
  font-size: 0.75rem;
}
.fd-breadcrumb-link {
  text-decoration: none;
}
.fd-breadcrumb-current {
  font-weight: 500;
}
```

#### Page Action Buttons

```css title="page-action-buttons.css"
.fd-page-action-btn {
  border-radius: 0.375rem;
  background: var(--color-fd-secondary);
  border: 1px solid var(--color-fd-border);
}

.fd-page-action-menu {
  border-radius: 0.5rem;
  background: var(--color-fd-popover);
}
```

#### Scrollbar

```css title="scrollbar.css"
.dark {
  --scrollbar-thumb: var(--color-fd-border);
  --scrollbar-thumb-hover: var(--color-fd-ring);
  --scrollbar-track: transparent;
}
```

#### Selection & Misc

```css title="selection-misc.css"
::selection {
  background: var(--color-fd-foreground);
  color: var(--color-fd-background);
}

.dark hr {
  border-color: hsl(0 0% 15%);
}
```

### Tips

- **Inspect in DevTools** — the fastest way to find the right selector is to right-click an element, inspect it, and check its classes/attributes.
- **Use `!important` sparingly** — fumadocs uses Tailwind utilities, so some overrides need `!important`. Check the built-in theme CSS files for examples.
- **Scope with `.dark`** — use `.dark` for dark mode styles. Fumadocs uses class-based dark mode.
- **Reference CSS variables** — always use `var(--color-fd-*)` in your styles so they respond to user color overrides.
- **Look at built-in themes** — the `pixel-border` and `darksharp` CSS files are excellent references showing every component selector in use.