DEV Community

Cover image for Dark Mode in 1 Line of Code — Meet vartheme
SUMIT
SUMIT

Posted on

Dark Mode in 1 Line of Code — Meet vartheme

If you've ever implemented dark mode in React, you already know the struggle.

You end up:

  • Setting up context
  • Writing localStorage logic
  • Handling system preferences
  • Fixing flash of white on load (FOUC)
  • Wiring CSS variables

And before you know it… you've written 200+ lines of boilerplate that has nothing to do with your actual app.

So I built vartheme.


🚨 The Problem With Dark Mode Today

Most developers fall into one of these approaches:

1. Roll Your Own

  • ❌ 200+ lines of code
  • ❌ Breaks in SSR / Next.js
  • ❌ Repeated effort every project

2. Use next-themes

  • ✅ Good library
  • ❌ Tied to Next.js
  • ❌ No CSS variables
  • ❌ No built-in UI

3. Use UI Library Themes

  • ❌ Locked into their design system
  • ❌ Limited flexibility

💡 What I Wanted

A solution that:

  • ✅ Works in any React setup (Vite, Next.js, Remix, CRA)
  • ✅ Uses CSS variables
  • ✅ Includes a beautiful toggle UI
  • ✅ Is SSR safe
  • ✅ Persists user preferences

⚡ Introducing vartheme

A simple, flexible, and powerful theming solution for React.


🚀 Dark Mode in 1 Line

npm install vartheme
Enter fullscreen mode Exit fullscreen mode
import { ThemeProvider, ThemeToggle } from 'vartheme'

export default function App() {
  return (
    <ThemeProvider>
      <ThemeToggle />
    </ThemeProvider>
  )
}
Enter fullscreen mode Exit fullscreen mode

That’s it.

You instantly get:

  • ✅ Light / Dark / System mode
  • ✅ Animated toggle (🌞 / 🌙)
  • ✅ localStorage + cookie persistence
  • ✅ CSS variables auto-injected
  • ✅ SSR safe

🎨 Using CSS Variables

.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

🎭 Built-in Themes

import { useThemeContext } from 'vartheme'

const { setTheme } = useThemeContext()

setTheme('ocean')
setTheme('forest')
Enter fullscreen mode Exit fullscreen mode

⚙️ Next.js (App Router) — Fully SSR Safe

const isBrowser = typeof window !== 'undefined'

export function saveMode(mode) {
  if (!isBrowser) return
  localStorage.setItem('vartheme-mode', mode)
}
Enter fullscreen mode Exit fullscreen mode
import { getFOUCScript } from 'vartheme'

export default function RootLayout({ children }) {
  return (
    <html>
      <head>{getFOUCScript()}</head>
      <body>{children}</body>
    </html>
  )
}
Enter fullscreen mode Exit fullscreen mode
import { cookies } from 'next/headers'
import { loadModeFromCookieString } from 'vartheme'

export default function RootLayout({ children }) {
  const mode =
    loadModeFromCookieString(cookies().toString()) || 'system'

  return <html data-theme={mode}>{children}</html>
}
Enter fullscreen mode Exit fullscreen mode

🧩 shadcn/ui & Radix UI Support

<ThemeProvider strategy="class" />
Enter fullscreen mode Exit fullscreen mode

🧠 useThemeContext Hook

import { useThemeContext } from 'vartheme'

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

  return (
    <button onClick={toggle}>
      {resolvedMode === 'dark' ? '☀️ Light' : '🌙 Dark'}
    </button>
  )
}
Enter fullscreen mode Exit fullscreen mode

🎨 Custom Colors

<ThemeProvider colors={{ primary: '#EC4899' }} />
Enter fullscreen mode Exit fullscreen mode

🌬 Tailwind Plugin

import { varthemePlugin } from 'vartheme/tailwind'

export default {
  plugins: [varthemePlugin],
}
Enter fullscreen mode Exit fullscreen mode

📦 Package Details

  • 📦 16.8kb
  • ⚡ Zero dependencies
  • 🧠 TypeScript support

🚀 Get Started

npm install vartheme
Enter fullscreen mode Exit fullscreen mode

❤️ Final Note

Built this because I was tired of rewriting the same dark mode logic in every project.

If this helps you:
👉 Drop a ⭐ on GitHub

👉 Share it with other devs 🚀

Top comments (0)