Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,10 @@ tests/visual/ Visual regression tests (Playwright + R2 baselines)
| Visual regression tests | `tests/visual/` (see its CLAUDE.md) |
| Document API contract | `packages/document-api/src/contract/operation-definitions.ts` |
| Adding a doc-api operation | See `packages/document-api/README.md` § "Adding a new operation" |
| Theming (`createTheme()`) | `packages/superdoc/src/core/theme/create-theme.js` |
| CSS variable defaults | `packages/superdoc/src/assets/styles/helpers/variables.css` |
| Preset themes | `packages/superdoc/src/assets/styles/helpers/themes.css` |
| Consumer-facing agent guide | `packages/superdoc/AGENTS.md` (ships with npm package) |

## Style Resolution Boundary

Expand Down
133 changes: 72 additions & 61 deletions apps/docs/getting-started/theming.mdx
Original file line number Diff line number Diff line change
@@ -1,32 +1,77 @@
---
title: Theming
sidebarTitle: Theming
keywords: "theming, css variables, custom theme, dark mode, design tokens, branding, css customization, styling"
keywords: "theming, css variables, custom theme, dark mode, design tokens, branding, css customization, createTheme, styling"
---

Change five CSS variables and your brand colors flow through every SuperDoc component — toolbar, comments, dropdowns, everything. No JavaScript needed.
Set your brand colors in JavaScript and every SuperDoc component updates — toolbar, comments, dropdowns, everything.

```css
.my-theme {
--sd-ui-action: #6366f1;
--sd-ui-action-hover: #4f46e5;
--sd-ui-toolbar-bg: #f8fafc;
--sd-ui-bg: #ffffff;
--sd-ui-text: #1e293b;
}
```javascript
import { createTheme } from 'superdoc';

const theme = createTheme({
colors: { action: '#6366f1', bg: '#ffffff', text: '#1e293b', border: '#e2e8f0' },
font: 'Inter, sans-serif',
});

document.documentElement.classList.add(theme);
```

```html
<html class="my-theme">
<div id="editor"></div>
</html>
Five properties theme the entire UI.

## `createTheme()`

Pass a config object, get back a CSS class name. Apply it to `<html>`.

```javascript
import { createTheme } from 'superdoc';

const theme = createTheme({
name: 'my-brand', // optional — generates sd-theme-my-brand
font: 'Inter, sans-serif',
radius: '8px',
colors: {
action: '#6366f1', // buttons, links, active states
actionHover: '#4f46e5',
bg: '#ffffff', // panels, cards, dropdowns
text: '#1e293b', // primary text
textMuted: '#64748b', // secondary text
border: '#e2e8f0', // all borders
},
// Escape hatch — any CSS variable
vars: {
'--sd-ui-toolbar-bg': '#f8fafc',
'--sd-ui-comments-card-bg': '#f0f0ff',
},
});

document.documentElement.classList.add(theme);
```

Override any `--sd-*` CSS custom property on the `<html>` element and the changes cascade to all components.
`colors` controls the semantic tier — every component inherits from it. The `vars` escape hatch lets you set any `--sd-*` CSS variable directly for fine-grained control.

## SSR support

Use `buildTheme()` to get the raw CSS string for server-side rendering:

```javascript
import { buildTheme } from 'superdoc';

const { className, css } = buildTheme({
colors: { action: '#6366f1', bg: '#ffffff', text: '#1e293b' },
});

const html = `
<html class="${className}">
<head><style>${css}</style></head>
<body><div id="editor"></div></body>
</html>
`;
```

## Preset themes

Three preset themes ship out of the box. Add the class to `<html>` — some SuperDoc elements (popovers, dropdowns) are appended to `<body>`, so they need to inherit from `<html>` to pick up the theme.
Three presets ship out of the box. Add the class to `<html>` — some SuperDoc elements (popovers, dropdowns) are appended to `<body>`, so they need to inherit from `<html>`.

<CardGroup cols={3}>
<Card title="Docs" icon="google">
Expand All @@ -49,55 +94,21 @@ Three preset themes ship out of the box. Add the class to `<html>` — some Supe
</Card>
</CardGroup>

You can layer your own overrides on top of a preset:
## CSS variables (advanced)

`createTheme()` generates CSS variables under the hood. You can also set them directly:

```css
.sd-theme-docs {
--sd-ui-action: #your-brand-color;
--sd-ui-comments-card-bg: #f0f0f0;
:root {
--sd-ui-action: #6366f1;
--sd-ui-bg: #ffffff;
--sd-ui-text: #1e293b;
--sd-ui-border: #e2e8f0;
--sd-ui-font-family: Inter, sans-serif;
}
```

## How the token system works

Variables are organized in three tiers. Higher tiers reference lower tiers, so changing a primitive cascades everywhere.

```
Primitives UI semantic Component-specific
--sd-color-* --sd-ui-text --sd-ui-toolbar-*
--sd-font-size-* --sd-ui-bg --sd-ui-comments-*
--sd-radius-* --sd-ui-action --sd-ui-dropdown-*
```

**Tier 1 — Primitives.** Raw color scales, font sizes, and radii. You rarely need to touch these directly.

**Tier 2 — UI semantic.** The "5-variable theme." Change these and every component updates:

| Variable | Default | What it controls |
|----------|---------|-----------------|
| `--sd-ui-font-family` | `Arial, Helvetica, sans-serif` | Font for all UI chrome |
| `--sd-ui-text` | `#47484a` | Primary text color |
| `--sd-ui-bg` | `#ffffff` | Panels, cards, dropdowns |
| `--sd-ui-border` | `#dbdbdb` | All borders |
| `--sd-ui-action` | `#1355ff` | Buttons, links, active states |

**Tier 3 — Component-specific.** Fine-grained overrides for individual components. These default to the semantic tier, so you only set them when a component needs to look different from the rest. See the [full reference](/guides/general/custom-themes).

## JavaScript config

The `trackChangesConfig` and `commentsConfig` JavaScript options still work. They take priority over CSS variables when set. Use the JS API for runtime changes, CSS variables for static theming.

```javascript
new SuperDoc({
selector: '#editor',
commentsConfig: {
highlightHoverColor: '#ff000055',
trackChangeHighlightColors: {
insertBorder: '#00ff00',
},
},
});
```
See the [full variable reference](/guides/general/custom-themes#variable-reference) for every token.

## Next steps

Expand All @@ -107,7 +118,7 @@ new SuperDoc({
icon="palette"
href="/guides/general/custom-themes"
>
Full variable reference by component. Dark theme starter. How to build your own preset.
Full API reference, dark theme starter, all CSS variables by component.
</Card>
<Card
title="Migration guide"
Expand Down
85 changes: 63 additions & 22 deletions apps/docs/guides/general/custom-themes.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -4,34 +4,75 @@ sidebarTitle: Custom themes
keywords: "custom theme, css variables reference, design tokens, theming guide, component styling, dark theme"
---

Every CSS variable you can override, organized by component. If you haven't set up theming yet, start with the [theming overview](/getting-started/theming).

## Creating a theme

Define a CSS class with your overrides. Apply it to the `<html>` element.

```css
.my-company-theme {
/* These cascade to every component */
--sd-ui-action: #8b5cf6;
--sd-ui-action-hover: #7c3aed;
--sd-ui-text: #1e293b;
--sd-ui-bg: #f8fafc;
--sd-ui-border: #e2e8f0;

/* Fine-tune where needed */
--sd-ui-toolbar-bg: #f1f5f9;
--sd-ui-comments-card-bg: #f0f0ff;
}
Full `createTheme()` API reference and CSS variable catalog. Start with the [theming overview](/getting-started/theming) if you're new to theming.

## `createTheme()` options

```javascript
import { createTheme } from 'superdoc';

const theme = createTheme({
name: 'my-brand',
font: 'Inter, sans-serif',
radius: '8px',
shadow: '0 2px 8px rgba(0,0,0,0.1)',
colors: {
action: '#6366f1', // buttons, links, active states
actionHover: '#4f46e5',
bg: '#ffffff', // panels, cards, dropdowns
hoverBg: '#f1f5f9', // hover backgrounds
activeBg: '#e2e8f0', // active/pressed backgrounds
disabledBg: '#f5f5f5',
text: '#1e293b', // primary text
textMuted: '#64748b', // secondary text
textDisabled: '#94a3b8',
border: '#e2e8f0',
},
// Escape hatch — any --sd-* CSS variable
vars: {
'--sd-ui-toolbar-bg': '#f8fafc',
'--sd-ui-comments-card-bg': '#f0f0ff',
},
});

document.documentElement.classList.add(theme);
```

<Tip>
Start with the 5-10 semantic variables. Add component-specific ones only where the defaults don't look right.
Start with `colors` only. Use `vars` when a specific component needs to look different.
</Tip>

## Dark theme starter
## Dark theme example

```javascript
import { createTheme } from 'superdoc';

const dark = createTheme({
name: 'dark',
colors: {
bg: '#1a1a2e',
hoverBg: '#2a2a3e',
activeBg: '#3a3a4e',
text: '#e2e8f0',
textMuted: '#94a3b8',
border: '#334155',
action: '#60a5fa',
actionHover: '#93c5fd',
},
vars: {
'--sd-ui-toolbar-bg': '#0f172a',
'--sd-ui-toolbar-button-text': '#e2e8f0',
'--sd-ui-comments-card-bg': '#1e293b',
'--sd-ui-comments-body-text': '#cbd5e1',
},
});

document.documentElement.classList.add(dark);
```

## Raw CSS alternative

Override the core surface and text variables. Component backgrounds cascade from `--sd-ui-bg` automatically.
You can also write CSS directly. Apply overrides to `<html>`.

```css
.dark-theme {
Expand Down
17 changes: 17 additions & 0 deletions examples/features/theming/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>SuperDoc — Theming</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
html, body, #root { height: 100%; }
body { font-family: system-ui, sans-serif; }
</style>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
21 changes: 21 additions & 0 deletions examples/features/theming/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"name": "superdoc-theming-example",
"private": true,
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build"
},
"dependencies": {
"react": "^19.2.1",
"react-dom": "^19.2.1",
"superdoc": "latest"
},
"devDependencies": {
"@types/react": "^19.2.7",
"@types/react-dom": "^19.2.3",
"@vitejs/plugin-react": "^5.1.2",
"typescript": "^5.9.3",
"vite": "^7.2.7"
}
}
Loading
Loading