Skip to content
Open
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
7 changes: 4 additions & 3 deletions packages/docs/docs.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,11 @@
"pages": [
"guides/mcp-server",
"guides/skills",
"guides/dark-mode",
"guides/component-docs",
"guides/accessibility",
"guides/testing",
"guides/publish-to-npm"
"guides/publish-to-npm",
"guides/dark-mode"
]
},
{
Expand Down Expand Up @@ -97,7 +97,8 @@
"learn/theme/customizing-theme",
"learn/theme/importing-tokens",
"learn/theme/exporting-theme",
"learn/theme/adding-custom-fonts"
"learn/theme/adding-custom-fonts",
"learn/theme/dark-mode"
]
},
"learn/flows/flows",
Expand Down
128 changes: 74 additions & 54 deletions packages/docs/guides/dark-mode.mdx
Original file line number Diff line number Diff line change
@@ -1,29 +1,14 @@
---
title: Dark mode
description: Add dark mode to your project using Subframe's built-in theme support
title: Dark mode toggle
description: Add a dark mode toggle to your app using Subframe's generated theme.
---

import CliSyncAllCommand from "/snippets/cli-sync-all-command.mdx"

Subframe has built-in dark mode support. Enable it in your theme to define light and dark values side by side, then sync to get a fully configured Tailwind setup.

## Enable dark mode

1. Open **Theme** in the top navigation
2. In the Colors section, click **Add dark mode**
3. Each token now shows light and dark values — edit the dark values to define your dark palette
4. Preview your components and pages in both light and dark mode using the light/dark mode toggle in the toolbar

<Tip>
Dark mode colors typically invert the scale: light mode's lightest shade becomes dark mode's darkest, and vice versa.
</Tip>

To remove dark mode, click **Remove dark mode** in the Colors section. This deletes all dark overrides. You can undo this using version history.
When you [enable dark mode](/learn/theme/dark-mode) in your theme, the CLI generates your color tokens as CSS variables instead of hardcoded values. Light mode values load by default, and dark mode values activate when a `dark` class is present on the page. This guide covers how to toggle between them.

## How the generated code works

When dark mode is enabled, Subframe generates theme tokens as CSS variables so light and dark values can switch at runtime.

<Tabs>
<Tab title="Tailwind v3">

Expand Down Expand Up @@ -90,22 +75,29 @@ The generated `theme.css` includes a `@custom-variant` for dark mode and a `.dar
</Tab>
</Tabs>

## Sync to code
## Sync your theme

Run the CLI to sync your theme (including dark mode) to your codebase:

<CliSyncAllCommand />

## Enable dark mode in your app
## Add a toggle

To activate dark mode, set the `dark` class on the `<html>` element. Here are a few ways to accomplish that:
To switch between light and dark mode, your app needs to toggle the `dark` class on the `<html>` element. Here's how to set that up:

### Next.js with next-themes
<Tabs>
<Tab title="Next.js (next-themes)">

<Steps>
<Step title="Install next-themes">

```bash
npm install next-themes
```

</Step>
<Step title="Wrap your app in the ThemeProvider">

```tsx app/layout.tsx
import { ThemeProvider } from "next-themes"

Expand All @@ -122,62 +114,90 @@ export default function RootLayout({ children }) {
}
```

### React with context
</Step>
<Step title="Add a toggle button">

```tsx
import { useTheme } from "next-themes"

export function ThemeToggle() {
const { theme, setTheme } = useTheme()

return (
<button onClick={() => setTheme(theme === "dark" ? "light" : "dark")}>
{theme === "dark" ? "Light mode" : "Dark mode"}
</button>
)
}
```

</Step>
</Steps>

</Tab>
<Tab title="Vite / React">

<Steps>
<Step title="Create a ThemeProvider">

```tsx ThemeProvider.tsx
import { createContext, useContext, useEffect, useState } from "react"

const ThemeContext = createContext({ theme: "light", toggleTheme: () => {} })

export function ThemeProvider({ children }) {
const [theme, setTheme] = useState("light")
const [theme, setTheme] = useState(() => {
if (typeof window !== "undefined") {
return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light"
}
return "light"
})

useEffect(() => {
const root = window.document.documentElement
root.classList.remove("light", "dark")
root.classList.add(theme)
document.documentElement.classList.remove("light", "dark")
document.documentElement.classList.add(theme)
}, [theme])

const toggleTheme = () => setTheme(theme === "light" ? "dark" : "light")

return <ThemeContext.Provider value={{ theme, toggleTheme }}>{children}</ThemeContext.Provider>
return <ThemeContext.Provider value=undefined>{children}</ThemeContext.Provider>
}

export const useTheme = () => useContext(ThemeContext)
```

### Theme toggle button

```tsx
import { useTheme } from "next-themes"
</Step>
<Step title="Wrap your app">

export function ThemeToggle() {
const { theme, setTheme } = useTheme()
```tsx main.tsx
import { ThemeProvider } from "./ThemeProvider"

return <button onClick={() => setTheme(theme === "dark" ? "light" : "dark")}>{theme === "dark" ? "☀️" : "🌙"}</button>
}
ReactDOM.createRoot(document.getElementById("root")!).render(
<ThemeProvider>
<App />
</ThemeProvider>
)
```

## Best practices

<AccordionGroup>
<Accordion title="Test both modes">

Always test your application in both light and dark modes. Check for:
</Step>
<Step title="Add a toggle button">

- Sufficient contrast ratios (use browser DevTools)
- Readability of all text
- Visibility of borders and dividers
- Proper styling of interactive states

</Accordion>
<Accordion title="Respect system preferences">
```tsx
import { useTheme } from "./ThemeProvider"

Use the user's system preference as the default:
export function ThemeToggle() {
const { theme, toggleTheme } = useTheme()

```tsx
<ThemeProvider attribute="class" defaultTheme="system">
return (
<button onClick={toggleTheme}>
{theme === "dark" ? "Light mode" : "Dark mode"}
</button>
)
}
```

</Accordion>
</AccordionGroup>
</Step>
</Steps>

</Tab>
</Tabs>
42 changes: 23 additions & 19 deletions packages/docs/learn/theme/customizing-theme.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ Click **Theme** in the top navigation, or press <kbd>Cmd</kbd> + <kbd>K</kbd> an

The theme page has a left sidebar for navigating between sections: Colors, Typography, Borders, Corners, and Shadows. Click any section to scroll to it.

The Colors section header contains the main actions: **Ask AI**, **Import tokens**, **Export**, and a **** menu with **Reset theme** and **Show version history**.
The Colors section header contains the main actions: **Ask AI**, **Import tokens**, **Export**, and a **⋯** menu with **Reset theme** and **Show version history**.

All changes save automatically and apply immediately across your project.

Expand All @@ -25,7 +25,7 @@ Use Ask AI to update your theme from a prompt:

1. Click **Ask AI** in the sidebar
2. Describe your changes: "warmer tones, rounder corners", "make it brutalist", or "retro theme with muted colors and bold typography"
3. Review the preview AI updates colors, typography, corners, and shadows
3. Review the preview — AI updates colors, typography, corners, and shadows
4. Click **Apply** to update your theme

Ask AI can also rename or delete tokens when the changes call for it. All component references update automatically.
Expand All @@ -42,9 +42,9 @@ Subframe organizes colors into **color tokens** grouped by **folders**.
<div className="bg-neutral-100 text-default-font">Neutral background with default text color</div>
```

**Color tokens** define individual colors for your design system. They can be used for specific UI purposes like Brand Primary, Default Background, or Neutral Border. Tokens can reference other tokens as aliases (e.g. Brand Primary Brand 700).
**Color tokens** define individual colors for your design system. They can be used for specific UI purposes like Brand Primary, Default Background, or Neutral Border. Tokens can reference other tokens as aliases (e.g. Brand Primary → Brand 700).

**Folders** group related color tokens together. Organize tokens however you want by brand, by feature, by shade scale, or any grouping that fits your system. A default **Colors** folder holds standalone tokens.
**Folders** group related color tokens together. Organize tokens however you want — by brand, by feature, by shade scale, or any grouping that fits your system. A default **Colors** folder holds standalone tokens.

To quickly add tokens from an existing design system, see [Importing tokens](/learn/theme/importing-tokens).

Expand All @@ -70,6 +70,10 @@ To quickly add tokens from an existing design system, see [Importing tokens](/le

Click any token to open color picker. Set a direct color value or reference another token as an alias.

### Dark mode

Enable dark mode to add separate light and dark values for each color token. See [Dark mode](/learn/theme/dark-mode) for details.

## Typography

Text tokens define typography styles with font family, size, weight, line height, and letter spacing.
Expand All @@ -91,10 +95,10 @@ New tokens duplicate the properties from the first token. Typography tokens auto

Click any text token to edit:

- **Font size** Pixel value
- **Line height** Pixel value
- **Font weight** Slider based on font's supported weights
- **Letter spacing** Slider from `-0.05em` to `0.05em`
- **Font size** — Pixel value
- **Line height** — Pixel value
- **Font weight** — Slider based on font's supported weights
- **Letter spacing** — Slider from `-0.05em` to `0.05em`

### Changing font families

Expand Down Expand Up @@ -131,9 +135,9 @@ When generating code, border styles turn into explicit values for the border:

Click any border token to edit:

- **Border style** Solid or dashed
- **Border size** Pixel width
- **Border color** Color token reference or direct value
- **Border style** — Solid or dashed
- **Border size** — Pixel width
- **Border color** — Color token reference or direct value

## Corners

Expand Down Expand Up @@ -177,11 +181,11 @@ Shadow tokens auto-sort based on perceived shadow effect.

Click any shadow token to edit individual shadow layers. Each layer has:

- **Inset** Whether shadow appears inside element
- **X/Y offset** Horizontal and vertical offset in pixels
- **Blur radius** Blur amount in pixels
- **Spread radius** Spread amount in pixels
- **Color** Shadow color with opacity
- **Inset** — Whether shadow appears inside element
- **X/Y offset** — Horizontal and vertical offset in pixels
- **Blur radius** — Blur amount in pixels
- **Spread radius** — Spread amount in pixels
- **Color** — Shadow color with opacity

Add multiple layers for complex shadow effects.

Expand All @@ -193,7 +197,7 @@ Add multiple layers for complex shadow effects.

Apply a theme preset to start fresh:

1. Click **** in the sidebar and select **Reset theme**
1. Click **⋯** in the sidebar and select **Reset theme**
2. Browse 10 preset styles
3. Customize brand colors, fonts, and corner radius
4. Toggle between Light and Dark mode
Expand All @@ -206,12 +210,12 @@ Each preset configures color palettes (brand, neutral, error, success, warning),

View and restore previous versions of your theme:

1. Click **** in the sidebar and select **Version history**
1. Click **⋯** in the sidebar and select **Version history**
2. Browse the timeline and select a version to preview
3. Click **Restore** to revert to that version

Select **Exit version history** from the same menu to return to editing.

## Limitations

**Spacing not configurable** Spacing tokens (padding, gaps) use Tailwind defaults. Extend your Tailwind config manually for custom spacing in your codebase.
**Spacing not configurable** — Spacing tokens (padding, gaps) use Tailwind defaults. Extend your Tailwind config manually for custom spacing in your codebase.
32 changes: 32 additions & 0 deletions packages/docs/learn/theme/dark-mode.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
---
title: Dark mode
description: Define light and dark color values for your theme.
---

import CliSyncAllCommand from "/snippets/cli-sync-all-command.mdx"

Your theme supports light and dark color modes. When dark mode is enabled, each color token has separate light and dark values.

## Adding dark mode

1. Open **Theme** in the top navigation
2. Click **Add dark mode** in the Colors section
3. Edit the dark value for each color token

{/* TODO: Add screenshot of dark mode color tokens */}

Preview your designs in dark mode using the light/dark toggle in the toolbar.

## Removing dark mode

Click **Remove dark mode** in the Colors section. This deletes all dark color overrides.

<Warning>Removing dark mode is destructive. Use [version history](/learn/projects/version-history) to restore if needed.</Warning>

## Code export

When dark mode is enabled, the CLI generates your color tokens as CSS variables. Light mode values load by default, and dark mode values activate when a `dark` class is present on the page. Run the CLI to sync:

<CliSyncAllCommand />

To add a dark mode toggle to your app, see the [Dark mode toggle](/guides/dark-mode) guide.
10 changes: 5 additions & 5 deletions packages/docs/learn/theme/exporting-theme.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ Your theme generates a Tailwind CSS configuration that your codebase uses for st

Click **Export** in the sidebar to view the generated Tailwind configuration for your theme. The dialog has two tabs:

- **Tailwind CSS v3** Shows a `tailwind.config.js` file with your tokens as a JavaScript module
- **Tailwind CSS v4** Shows a `theme.css` file with your tokens as CSS variables inside a `@theme` block
- **Tailwind CSS v3** — Shows a `tailwind.config.js` file with your tokens as a JavaScript module
- **Tailwind CSS v4** — Shows a `theme.css` file with your tokens as CSS variables inside a `@theme` block

Click **Copy to clipboard** to copy either format.

Expand All @@ -22,10 +22,10 @@ Click **Copy to clipboard** to copy either format.

The generated config includes colors, font sizes, font families, box shadows, border radius, container settings, and responsive breakpoints.

When [dark mode](/guides/dark-mode) is enabled, the export includes additional dark mode overrides:
When [dark mode](/learn/theme/dark-mode) is enabled, the export includes additional dark mode overrides:

- **Tailwind v3** An additional `theme.css` file with `:root` and `.dark` CSS variable blocks, and `darkMode: 'selector'` in the config
- **Tailwind v4** A `.dark` block and `@custom-variant dark` declaration in the `theme.css` file
- **Tailwind v3** — An additional `theme.css` file with `:root` and `.dark` CSS variable blocks, and `darkMode: 'selector'` in the config
- **Tailwind v4** — A `.dark` block and `@custom-variant dark` declaration in the `theme.css` file

## Sync to code

Expand Down
Loading