@mdxui/themes
v0.0.1
Published
Design tokens, CSS variables, and theme management for mdxui
Readme
@mdxui/themes
Design tokens, CSS variables, and theme management for mdxui applications.
Installation
npm install @mdxui/themes
# or
pnpm add @mdxui/themes
# or
yarn add @mdxui/themesFeatures
- 30 built-in theme presets with light and dark mode support
- Zustand-powered state management with localStorage persistence
- FOUC prevention with SSR-compatible theme script
- CSS variable system for easy customization
- TypeScript-first with full type safety and autocomplete
Quick Start
1. Add the Theme Script (Prevents Flash)
Add ThemeScript to your document head to prevent flash of unstyled content:
// Next.js App Router (layout.tsx)
import { ThemeScript } from '@mdxui/themes'
export default function RootLayout({ children }) {
return (
<html lang="en" suppressHydrationWarning>
<head>
<ThemeScript />
</head>
<body>{children}</body>
</html>
)
}2. Import a Theme CSS File
// Import a theme preset
import '@mdxui/themes/css/stripe.css'
// Or dynamically based on selection
import `@mdxui/themes/css/${themeName}.css`3. Use the Theme Store
import { useThemeStore } from '@mdxui/themes'
function ThemeToggle() {
const { preset, mode, setPreset, setMode } = useThemeStore()
return (
<div>
<select value={preset} onChange={(e) => setPreset(e.target.value)}>
<option value="stripe">Stripe</option>
<option value="linear">Linear</option>
<option value="anthropic">Anthropic</option>
</select>
<select value={mode} onChange={(e) => setMode(e.target.value)}>
<option value="light">Light</option>
<option value="dark">Dark</option>
<option value="system">System</option>
</select>
</div>
)
}Available Themes
30 built-in theme presets, each with light and dark mode:
| Theme | Description |
|-------|-------------|
| anthropic | Anthropic brand colors |
| arc | Arc browser inspired |
| airbnb | Airbnb brand colors |
| aurora | Northern lights palette |
| blueprint | Technical blueprint style |
| bubblegum | Playful pink tones |
| bumble | Bumble brand colors |
| cappuccino | Warm coffee tones |
| clay | Earthy clay palette |
| cyan | Vibrant cyan accent |
| dev | Developer-focused theme |
| dusk | Sunset gradient tones |
| ember | Warm ember/fire colors |
| frost | Cool icy blues |
| linear | Linear app inspired |
| midnight | Deep midnight blues |
| mocha | Rich mocha browns |
| monica | Monica brand colors |
| mono | Monochrome grayscale |
| neural | AI/neural network style |
| notation | Notion-inspired theme |
| notepad | Classic notepad style |
| obsidian | Obsidian app inspired |
| phosphor | Phosphor green terminal |
| polaris | Shopify Polaris colors |
| sage | Soft sage greens |
| star | Starry night palette |
| starlink | SpaceX Starlink theme |
| stripe | Stripe brand colors |
| x | X/Twitter brand colors |
Usage Patterns
Static Theme (CSS Import)
For applications with a single theme:
// Import once at app root
import '@mdxui/themes/css/stripe.css'
function App() {
return <div className="dark">Dark mode content</div>
}Dynamic Theme Switching
For applications that need runtime theme changes:
import { useThemeStore, themePresets } from '@mdxui/themes'
import { useEffect } from 'react'
function App() {
const { initialize } = useThemeStore()
useEffect(() => {
initialize() // Sets up system preference listener
}, [initialize])
return <ThemeSelector />
}
function ThemeSelector() {
const { preset, setPreset } = useThemeStore()
return (
<select value={preset} onChange={(e) => setPreset(e.target.value)}>
{themePresets.map((theme) => (
<option key={theme} value={theme}>{theme}</option>
))}
</select>
)
}Server-Side Rendering
For SSR frameworks, use the theme script to prevent hydration mismatch:
// Next.js Pages Router (_document.tsx)
import { ThemeScript } from '@mdxui/themes'
export default function Document() {
return (
<Html suppressHydrationWarning>
<Head>
<ThemeScript defaultMode="system" />
</Head>
<body>
<Main />
<NextScript />
</body>
</Html>
)
}Apply Theme to Specific Element
For isolated theme contexts (iframes, portals, previews):
import { applyThemeToElement } from '@mdxui/themes'
function Preview({ theme, mode }) {
const ref = useRef<HTMLDivElement>(null)
useEffect(() => {
if (ref.current) {
applyThemeToElement(ref.current, theme, mode)
}
}, [theme, mode])
return <div ref={ref}>Themed content</div>
}Access Raw CSS Content
For programmatic CSS manipulation:
import { getThemeCSS, themeCSS } from '@mdxui/themes'
// Get CSS for a specific theme
const stripeCSS = getThemeCSS('stripe')
// Access all themes
Object.entries(themeCSS).forEach(([name, css]) => {
console.log(`Theme: ${name}, CSS length: ${css.length}`)
})Parse Theme Variables
Extract CSS variables for custom processing:
import { parseThemeCSS, getThemeCSS } from '@mdxui/themes'
const css = getThemeCSS('stripe')
const { light, dark } = parseThemeCSS(css)
console.log(light['--primary']) // Primary color in light mode
console.log(dark['--primary']) // Primary color in dark modeAPI Reference
Types
type ThemePreset = 'stripe' | 'linear' | 'anthropic' | ... // 30 presets
type Theme = ThemePreset | string // Allows custom themes
type ThemeMode = 'light' | 'dark' | 'system'
interface ThemeState {
preset: ThemePreset
mode: ThemeMode
resolvedMode: 'light' | 'dark'
}
interface ThemeStore extends ThemeState {
setPreset: (preset: ThemePreset) => void
setMode: (mode: ThemeMode) => void
applyTheme: () => void
initialize: () => void
}Hooks
useThemeStore()
Zustand store hook for theme state management.
const {
preset, // Current theme preset
mode, // Current mode setting
resolvedMode, // Computed mode (light/dark)
setPreset, // Change theme preset
setMode, // Change mode
applyTheme, // Manually apply current theme
initialize, // Initialize store and listeners
} = useThemeStore()Components
<ThemeScript />
SSR-safe script component for FOUC prevention.
<ThemeScript
defaultMode="system" // Default: 'system'
storageKey="theme-state" // Default: 'do-theme-state'
nonce={cspNonce} // Optional CSP nonce
/>Functions
applyThemeToElement(element, preset, mode)
Apply theme CSS variables to a specific DOM element.
getThemeCSS(preset)
Get raw CSS string for a theme preset.
parseThemeCSS(css)
Parse CSS string into light/dark variable objects.
isThemePreset(string)
Type guard to check if string is a valid preset.
getResolvedMode(mode)
Resolve 'system' mode to actual 'light' or 'dark'.
Constants
import {
themePresets, // Array of all preset names
themeNames, // Map of preset to display name
defaultThemeState, // Default state object
THEME_STORAGE_KEY, // LocalStorage key
DARK_MODE_CLASS, // CSS class for dark mode ('dark')
} from '@mdxui/themes'CSS Variables
Each theme defines CSS custom properties on :root (light) and .dark (dark mode):
:root {
--background: 0 0% 100%;
--foreground: 222.2 84% 4.9%;
--primary: 221.2 83.2% 53.3%;
--primary-foreground: 210 40% 98%;
/* ... and more */
}
.dark {
--background: 222.2 84% 4.9%;
--foreground: 210 40% 98%;
/* ... dark mode overrides */
}Use in your CSS/Tailwind:
.my-button {
background: hsl(var(--primary));
color: hsl(var(--primary-foreground));
}Integration with Tailwind CSS
The themes work seamlessly with Tailwind CSS v4:
/* globals.css */
@import "tailwindcss";
@import "@mdxui/themes/css/stripe.css";Or with Tailwind v3, extend your config:
// tailwind.config.js
module.exports = {
theme: {
extend: {
colors: {
background: 'hsl(var(--background))',
foreground: 'hsl(var(--foreground))',
primary: {
DEFAULT: 'hsl(var(--primary))',
foreground: 'hsl(var(--primary-foreground))',
},
// ... etc
},
},
},
}License
MIT
