DEV Community

Cover image for Dark mode in React is painful. So I built vartheme to fix it.
SUMIT
SUMIT

Posted on

Dark mode in React is painful. So I built vartheme to fix it.

If you've ever tried adding dark mode to a React app… you know the pain.

You configure Tailwind’s darkMode.
Then you write CSS variables manually.
Then you handle localStorage so the theme persists.
Then you fix the flash of the wrong theme on page load.
Then system theme detection breaks.
Then your navbar is still white in dark mode 😅

Sound familiar?

I got tired of repeating this in every project. So I built vartheme — a tiny React library that handles all of this in one line.


🚀 What is vartheme?

vartheme is a zero-config, CSS variable based theme switching library for React.

✅ Dark mode in one line
✅ 5 beautiful built-in themes
✅ Animated sun/moon toggle (no icon library needed)
✅ Theme persists automatically
✅ System theme detection
✅ Under 7kb bundle
✅ Zero dependencies
✅ Full TypeScript support


😩 The Problem

Without vartheme, adding dark mode usually looks like this:

// 1. Setup Tailwind config
// 2. Write CSS variables manually
// 3. Handle localStorage
// 4. Fix flash of wrong theme
// 5. Handle system theme detection
// 6. Write a toggle component
// 7. Debug for 2 hours
// 8. Still not working properly
Enter fullscreen mode Exit fullscreen mode

✅ The Solution

With vartheme:

import { ThemeProvider } from 'vartheme'

export default function App() {
  return (
    <ThemeProvider theme="ocean" mode="dark">
      <YourApp />
    </ThemeProvider>
  )
}
Enter fullscreen mode Exit fullscreen mode

That’s it. Dark mode done.


🎨 Built-in Themes

vartheme comes with 5 ready-to-use themes:

• Default — Purple/Violet
• Ocean — Blue/Teal
• Forest — Green/Lime
• Sunset — Orange/Pink
• Rose — Pink/Red

Switch themes instantly:

<ThemeProvider theme="forest">
Enter fullscreen mode Exit fullscreen mode

🎯 CSS Variables (Use anywhere)

.card {
  background: var(--vt-surface);
  color: var(--vt-text);
  border: 1px solid var(--vt-border);
}

.button {
  background: var(--vt-primary);
  color: white;
}
Enter fullscreen mode Exit fullscreen mode

No more hardcoding colors. No more theme context headaches.


⚡ Powerful Hook

Need more control?

import { useThemeContext } from 'vartheme'

function Navbar() {
  const { resolvedMode, toggle, setTheme, setColors } = useThemeContext()

  return (
    <div>
      <button onClick={toggle}>
        {resolvedMode === 'dark' ? '☀️' : '🌙'}
      </button>

      <button onClick={() => setTheme('ocean')}>Ocean</button>

      <button onClick={() => setColors({ primary: '#EC4899' })}>
        Pink Mode
      </button>
    </div>
  )
}
Enter fullscreen mode Exit fullscreen mode

🌙 Built-in Animated Toggle

No icons. Pure CSS.

import { ThemeToggle } from 'vartheme'

<ThemeToggle size={48} />
Enter fullscreen mode Exit fullscreen mode

📦 Install

npm install vartheme
Enter fullscreen mode Exit fullscreen mode

Bundle size: ~7kb. Zero dependencies. TypeScript ready.


🔗 Links

📦 npm: https://www.npmjs.com/package/vartheme
🔷 GitHub: https://github.com/sumitt-wayne/vartheme
🌐 Website: https://vartheme.vercel.app


If you find it useful, drop a ⭐ on GitHub — it really means a lot!

What features would you like to see next? Let me know in the comments 👇

Top comments (0)