Skip to content
Emilio Romero edited this page Jun 9, 2026 · 24 revisions

React

import { createContext, useContext, useState, type ReactNode } from 'react';
import Umbra, { type Options } from '@emrocode/umbra';

const options: Partial<Options> = {
  autoMatchTheme: true,
  // useColorScheme: ['#ffffff', '#000000'],
  // useStorage: 'local',
  // usePlugins: []
}

let umb = new Umbra(options);

const ThemeContext = createContext<{
  theme: string;
  toggleTheme: () => void;
} | null>(null);

export const ThemeProvider = ({ children }: { children: ReactNode }) => {
  const [theme, setTheme] = useState<string>(umb.getCurrentTheme());

  const toggleTheme = () => {
    umb.toggleTheme();
    setTheme(umb.getCurrentTheme());
  };

  return (
    <ThemeContext.Provider value={{ theme, toggleTheme }}>
      {children}
    </ThemeContext.Provider>
  );
};

export const useTheme = () => {
  const context = useContext(ThemeContext);
  if (!context) {
    throw new Error('useTheme must be used within a ThemeProvider');
  }
  return context;
};

Next.js

To prevent the Flash of Unstyled Content (FOUC) when using Umbra with Server-Side Rendering (SSR) in Next.js, you must inject an inline, blocking script into your RootLayout. This ensures the user's preferred theme is applied to the HTML document before the browser renders the page.

Important

Add the "use client" directive to the top of any theme toggle or provider that interacts with localStorage or Umbra dynamically. Keep RootLayout as a Server Component to preserve optimal caching and SEO performance.

Implement this structure in your app/layout.tsx file:

// app/layout.tsx
export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <html lang="en" suppressHydrationWarning>
      <head>
        <script
          dangerouslySetInnerHTML={{
            __html: `(function(){try{var t=localStorage.getItem("theme");if(t)document.documentElement.setAttribute("data-theme",t)}catch(e){}})()`,
          }}
        />
      </head>
      <body>{children}</body>
    </html>
  )
}

TailwindCSS

v3.x

// tailwind.config.js
darkMode: ['selector', '[data-theme="dark"]']

v4.x

@import "tailwindcss";

@custom-variant dark (&:where([data-theme=dark], [data-theme=dark] *));

@theme {
  --color-background: #fff;
  --color-foreground: #000;
}

@variant dark {
  --color-background: #000;
  --color-foreground: #fff;
}

@layer base {
  html,
  body {
    @apply bg-background text-foreground;
  }
}

Clone this wiki locally