Type-safe, modular, and instant theme switching for React & Tailwind CSS v4
Features • Installation • Quick Start • API • Demo • Türkçe
- 🚀 Zero Runtime Overhead - Uses CSS variables for instant theme switching
- 📦 TypeScript First - Full type safety with autocomplete support
- 🎨 Tailwind CSS v4 Ready - Seamless integration with the new engine
- 💾 Persistent Themes - LocalStorage support out of the box
- 🌙 System Theme Detection - Respects
prefers-color-scheme - ⚡ No Flash - SSR compatible with hydration flash prevention
- 🎯 Scoped Theming - Apply different themes to different parts of your app
- 🧩 Ready-to-use Components -
ThemeSwitcherandThemeToggleincluded
npm install reactive-switcher
# or
pnpm add reactive-switcher
# or
yarn add reactive-switcher// themes.ts
import { ThemesConfig } from "reactive-switcher";
export const themes: ThemesConfig = {
light: {
name: "light",
type: "light",
colors: {
background: "#ffffff",
foreground: "#0f172a",
primary: {
DEFAULT: "#3b82f6",
foreground: "#ffffff",
50: "#eff6ff",
500: "#3b82f6",
600: "#2563eb",
},
secondary: {
DEFAULT: "#64748b",
foreground: "#ffffff",
},
surface: {
50: "#f8fafc",
100: "#f1f5f9",
200: "#e2e8f0",
},
},
},
dark: {
name: "dark",
type: "dark",
colors: {
background: "#020617",
foreground: "#f8fafc",
primary: {
DEFAULT: "#60a5fa",
foreground: "#0f172a",
},
secondary: {
DEFAULT: "#94a3b8",
foreground: "#0f172a",
},
surface: {
50: "#0f172a",
100: "#1e293b",
200: "#334155",
},
},
},
};// app/layout.tsx (Next.js)
import { ThemeProvider } from "reactive-switcher";
import { themes } from "./themes";
export default function RootLayout({ children }) {
return (
<html lang="en" suppressHydrationWarning>
<body>
<ThemeProvider themes={themes} defaultTheme="light">
{children}
</ThemeProvider>
</body>
</html>
);
}"use client";
import { useTheme, ThemeToggle } from "reactive-switcher";
export function Header() {
const { theme, setTheme, toggleTheme } = useTheme();
return (
<header className="bg-background text-foreground">
<p>Current Theme: {theme}</p>
{/* Ready-to-use toggle */}
<ThemeToggle />
{/* Or manual control */}
<button onClick={() => setTheme("dark")}>Dark</button>
<button onClick={toggleTheme}>Toggle</button>
</header>
);
}/* globals.css */
@import "tailwindcss";
@theme {
--color-background: var(--color-background);
--color-foreground: var(--color-foreground);
--color-primary: var(--color-primary-DEFAULT);
--color-primary-foreground: var(--color-primary-foreground);
--color-secondary: var(--color-secondary-DEFAULT);
--color-surface-50: var(--color-surface-50);
--color-surface-100: var(--color-surface-100);
--color-surface-200: var(--color-surface-200);
}
@layer base {
body {
background-color: var(--color-background);
color: var(--color-foreground);
transition: background-color 0.3s, color 0.3s;
}
}| Prop | Type | Default | Description |
|---|---|---|---|
themes |
ThemesConfig |
required | Theme configurations object |
defaultTheme |
string |
"light" |
Initial theme name |
enableStorage |
boolean |
true |
Persist theme to localStorage |
storageKey |
string |
"reactive-switcher-theme" |
localStorage key |
enableSystem |
boolean |
true |
Detect system color scheme |
selector |
string |
":root" |
CSS selector for scoped theming |
styleId |
string |
"reactive-switcher-styles" |
Style tag ID |
attribute |
"class" | "data-theme" |
"class" |
HTML attribute for theme |
const {
theme, // Current theme name (string)
resolvedTheme, // Actual theme (resolves "system")
setTheme, // (name: string) => void
toggleTheme, // () => void - Cycle through themes
themes, // Available theme names (string[])
systemTheme, // System preference ("light" | "dark")
} = useTheme();import { ThemeSwitcher, ThemeToggle } from "reactive-switcher";
// Dropdown/Button switcher with multiple variants
<ThemeSwitcher variant="buttons" /> // Side-by-side buttons
<ThemeSwitcher variant="dropdown" /> // Dropdown menu
<ThemeSwitcher variant="toggle" /> // Toggle button
// Simple two-theme toggle
<ThemeToggle />Apply different themes to different parts of your app:
import { ThemeProvider } from "reactive-switcher";
import { themes } from "./themes";
function App() {
return (
<ThemeProvider themes={themes} defaultTheme="light">
<main>Main content with light theme</main>
{/* Scoped dark theme section */}
<ThemeProvider
themes={themes}
defaultTheme="dark"
selector="#preview-panel"
enableStorage={false}
>
<div id="preview-panel">This section has its own theme!</div>
</ThemeProvider>
</ThemeProvider>
);
}Define nested color tokens:
const themes: ThemesConfig = {
ocean: {
name: "ocean",
type: "dark",
colors: {
background: "#042f2e",
foreground: "#ccfbf1",
primary: {
DEFAULT: "#2dd4bf",
foreground: "#042f2e",
50: "#042f2e",
100: "#115e59",
200: "#0f766e",
// ... more shades
},
accent: {
DEFAULT: "#facc15",
foreground: "#422006",
},
},
},
};Check out the live demo: reactive-switcher.vercel.app
Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
MIT © Poyraz Avsever
React ve Tailwind CSS v4 için tip güvenli, modüler ve anlık tema değiştirici
- 🚀 Sıfır Çalışma Zamanı Yükü - Anlık tema değişimi için CSS değişkenleri kullanır
- 📦 TypeScript Öncelikli - Otomatik tamamlama desteği ile tam tip güvenliği
- 🎨 Tailwind CSS v4 Uyumlu - Yeni motor ile kusursuz entegrasyon
- 💾 Kalıcı Temalar - Kutudan çıktığı gibi localStorage desteği
- 🌙 Sistem Teması Algılama -
prefers-color-schemetercihine uyar - ⚡ Yanıp Sönme Yok - SSR uyumlu, hidrasyon flash önleme
- 🎯 Kapsamlı Tema - Uygulamanızın farklı bölümlerine farklı temalar uygulayın
- 🧩 Kullanıma Hazır Bileşenler -
ThemeSwitcherveThemeToggledahil
npm install reactive-switcher
# veya
pnpm add reactive-switcher
# veya
yarn add reactive-switcher// themes.ts
import { ThemesConfig } from "reactive-switcher";
export const themes: ThemesConfig = {
light: {
name: "light",
type: "light",
colors: {
background: "#ffffff",
foreground: "#0f172a",
primary: {
DEFAULT: "#3b82f6",
foreground: "#ffffff",
50: "#eff6ff",
500: "#3b82f6",
600: "#2563eb",
},
secondary: {
DEFAULT: "#64748b",
foreground: "#ffffff",
},
surface: {
50: "#f8fafc",
100: "#f1f5f9",
200: "#e2e8f0",
},
},
},
dark: {
name: "dark",
type: "dark",
colors: {
background: "#020617",
foreground: "#f8fafc",
primary: {
DEFAULT: "#60a5fa",
foreground: "#0f172a",
},
secondary: {
DEFAULT: "#94a3b8",
foreground: "#0f172a",
},
surface: {
50: "#0f172a",
100: "#1e293b",
200: "#334155",
},
},
},
};// app/layout.tsx (Next.js)
import { ThemeProvider } from "reactive-switcher";
import { themes } from "./themes";
export default function RootLayout({ children }) {
return (
<html lang="tr" suppressHydrationWarning>
<body>
<ThemeProvider themes={themes} defaultTheme="light">
{children}
</ThemeProvider>
</body>
</html>
);
}"use client";
import { useTheme, ThemeToggle } from "reactive-switcher";
export function Header() {
const { theme, setTheme, toggleTheme } = useTheme();
return (
<header className="bg-background text-foreground">
<p>Aktif Tema: {theme}</p>
{/* Kullanıma hazır toggle */}
<ThemeToggle />
{/* Veya manuel kontrol */}
<button onClick={() => setTheme("dark")}>Koyu</button>
<button onClick={toggleTheme}>Değiştir</button>
</header>
);
}/* globals.css */
@import "tailwindcss";
@theme {
--color-background: var(--color-background);
--color-foreground: var(--color-foreground);
--color-primary: var(--color-primary-DEFAULT);
--color-primary-foreground: var(--color-primary-foreground);
--color-secondary: var(--color-secondary-DEFAULT);
--color-surface-50: var(--color-surface-50);
--color-surface-100: var(--color-surface-100);
--color-surface-200: var(--color-surface-200);
}
@layer base {
body {
background-color: var(--color-background);
color: var(--color-foreground);
transition: background-color 0.3s, color 0.3s;
}
}| Prop | Tip | Varsayılan | Açıklama |
|---|---|---|---|
themes |
ThemesConfig |
zorunlu | Tema yapılandırma objesi |
defaultTheme |
string |
"light" |
Başlangıç teması |
enableStorage |
boolean |
true |
localStorage'a kaydet |
storageKey |
string |
"reactive-switcher-theme" |
localStorage anahtarı |
enableSystem |
boolean |
true |
Sistem teması algılama |
selector |
string |
":root" |
Kapsamlı tema için CSS seçici |
const {
theme, // Aktif tema adı (string)
resolvedTheme, // Gerçek tema ("system" çözümlenir)
setTheme, // (name: string) => void
toggleTheme, // () => void - Temalar arasında geçiş
themes, // Mevcut tema adları (string[])
systemTheme, // Sistem tercihi ("light" | "dark")
} = useTheme();Canlı demoyu inceleyin: reactive-switcher.vercel.app
Katkılarınızı bekliyoruz! Pull Request göndermekten çekinmeyin.
- Repoyu fork edin
- Feature branch oluşturun (
git checkout -b feature/harika-ozellik) - Değişikliklerinizi commit edin (
git commit -m 'Harika özellik ekle') - Branch'i push edin (
git push origin feature/harika-ozellik) - Pull Request açın
MIT © Poyraz Avsever
Made with ❤️ by Poyraz Avsever