vartheme
v0.1.7
Published
Zero config, CSS variable based theme switching for React
Maintainers
Readme
vartheme ✨
Zero-config, CSS variable based theme switching for React
Dark mode in one line. Clean. Fast. Modern.
🌐 Website: vartheme.vercel.app
🚀 Why vartheme?
Most theme libraries are either:
- ❌ Complex to set up
- ❌ Not SSR safe (crashes in Next.js)
- ❌ Not CSS variable friendly
- ❌ Missing built-in UI components
vartheme solves this.
👉 Zero configuration
👉 SSR safe — works with Next.js App Router
👉 CSS variables by default
👉 Cookie + localStorage persistence
👉 Built-in animated toggle
👉 System theme detection
👉 FOUC prevention built-in
👉 Works with shadcn/ui, Radix, DaisyUI, Tailwind
👉 TypeScript ready
👉 16.8KB package size
⚡ Quick Start
npm install varthemeimport { ThemeProvider, ThemeToggle } from 'vartheme'
export default function App() {
return (
<ThemeProvider>
<ThemeToggle />
</ThemeProvider>
)
}That's it. Dark mode is done.
📊 Comparison
| Feature | vartheme | next-themes | manual | |---------|----------|-------------|--------| | Zero config | ✅ | ❌ | ❌ | | SSR safe | ✅ | ✅ | ❌ | | CSS variables | ✅ | ❌ | ✅ | | FOUC prevention | ✅ | ✅ | ❌ | | Cookie persistence | ✅ | ❌ | ❌ | | System detect | ✅ | ✅ | ❌ | | Built-in toggle UI | ✅ | ❌ | ❌ | | Named themes | ✅ | ❌ | ❌ | | shadcn/Radix support | ✅ | ✅ | ❌ |
🔧 Setup
React / Vite
// main.tsx
import { ThemeProvider } from 'vartheme'
function Main() {
return (
<ThemeProvider mode="system" transitions>
<App />
</ThemeProvider>
)
}Next.js App Router (SSR safe)
Step 1 — Prevent FOUC in layout.tsx:
import { getFOUCScript } from 'vartheme'
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html>
<head>
<script dangerouslySetInnerHTML={{ __html: getFOUCScript() }} />
</head>
<body>{children}</body>
</html>
)
}Step 2 — Read theme on server side:
import { cookies } from 'next/headers'
import { loadModeFromCookieString } from 'vartheme'
export default function RootLayout({ children }: { children: React.ReactNode }) {
const cookieHeader = cookies().toString()
const mode = loadModeFromCookieString(cookieHeader) || 'system'
return (
<html data-theme={mode}>
<body>
<ThemeProvider mode={mode}>
{children}
</ThemeProvider>
</body>
</html>
)
}🎨 Built-in Themes
<ThemeProvider theme="default"> // purple — default
<ThemeProvider theme="ocean"> // blue
<ThemeProvider theme="forest"> // green
<ThemeProvider theme="sunset"> // orange
<ThemeProvider theme="rose"> // pink🎯 Custom Colors
<ThemeProvider
colors={{
primary: '#EC4899',
accent: '#F59E0B',
}}
>
<App />
</ThemeProvider>Dynamic at runtime:
const { setColors } = useThemeContext()
setColors({ primary: '#10B981' })🔌 shadcn/ui + Radix support
// class="dark" strategy — shadcn/ui ke liye
<ThemeProvider strategy={{ type: 'class' }}>
// data-theme="dark" + class="dark" — dono saath
<ThemeProvider strategy={{ type: 'both' }}>
// Custom attribute
<ThemeProvider strategy={{ type: 'data-attribute', attribute: 'data-mode' }}>📡 onThemeChange callback
<ThemeProvider
onThemeChange={(mode) => {
console.log('Theme changed:', mode)
analytics.track('theme_switch', { mode })
}}
>🪝 useThemeContext hook
import { useThemeContext } from 'vartheme'
function Navbar() {
const { resolvedMode, toggle, setMode, setTheme, setColors } = useThemeContext()
return (
<button onClick={toggle}>
{resolvedMode === 'dark' ? '☀️ Light' : '🌙 Dark'}
</button>
)
}🎛️ ThemeToggle
import { ThemeToggle } from 'vartheme'
// Default size
<ThemeToggle />
// Custom size
<ThemeToggle size={64} />🎨 CSS Variables
.card {
background: var(--vt-surface);
color: var(--vt-text);
border: 1px solid var(--vt-border);
}| Variable | Light | Dark |
|----------|-------|------|
| --vt-primary | #7C3AED | #A78BFA |
| --vt-background | #FFFFFF | #0F172A |
| --vt-surface | #F8FAFC | #1E293B |
| --vt-text | #0F172A | #F8FAFC |
| --vt-border | #E2E8F0 | #334155 |
| --vt-accent | #06B6D4 | #22D3EE |
🌀 Tailwind Plugin
// tailwind.config.js
import { varthemePlugin } from 'vartheme/tailwind'
export default {
plugins: [varthemePlugin],
}<div className="bg-vt-surface text-vt-text border border-vt-border">
<h1 className="text-vt-primary">Hello!</h1>
<button className="bg-vt-primary text-white">Click me</button>
</div>| Class | CSS Variable |
|-------|-------------|
| bg-vt-primary | --vt-primary |
| bg-vt-background | --vt-background |
| bg-vt-surface | --vt-surface |
| text-vt-text | --vt-text |
| text-vt-primary | --vt-primary |
| text-vt-accent | --vt-accent |
| border-vt-border | --vt-border |
| shadow-vt-glow | --vt-primary glow |
🧩 TypeScript
import type { ThemeMode, ThemeColors, ThemeConfig, ThemeName, AttributeStrategy } from 'vartheme'🧠 API Reference
ThemeProvider props
| Prop | Type | Default |
|------|------|---------|
| mode | 'light' \| 'dark' \| 'system' | 'system' |
| theme | 'default' \| 'ocean' \| 'forest' \| 'sunset' \| 'rose' | 'default' |
| colors | ThemeColors | {} |
| transitions | boolean | false |
| strategy | AttributeStrategy | { type: 'data-attribute' } |
| onThemeChange | (mode: 'light' \| 'dark') => void | — |
useThemeContext returns
| Property | Type |
|----------|------|
| mode | ThemeMode |
| resolvedMode | 'light' \| 'dark' |
| theme | ThemeName |
| colors | ThemeColors |
| toggle() | () => void |
| setMode() | (mode: ThemeMode) => void |
| setTheme() | (theme: ThemeName) => void |
| setColors() | (colors: ThemeColors) => void |
🌍 Use Cases
- SaaS dashboards
- Design systems
- Portfolios
- Startups
- Component libraries
- Large scale apps
🤝 Contributing
We welcome contributions. Open issues, submit PRs, or suggest ideas.
⭐ Support
If you like this project:
- ⭐ Star the repo
- 🐦 Share on Twitter
- 💬 Tell your friends
- 🚀 Help grow the community
📄 License
MIT © 2026 vartheme
