Easily add 43+ themes with support for light and dark modes. Add a complete theme picker to your shadcn/ui app with a single command. Custom fonts, light & dark modes for every theme, and every theme available in OKLCH, HSL, HEX, or RGB for Tailwind CSS v4 (default) or v3.
This project is not affiliated with tweakcn. Themes are inspired by and adapted from the tweakcn theme collection.
- 43+ ready-to-use themes
- Light and dark mode support for each theme
- Framework adapters for Next.js, Vite, Astro, and Remix
- Tailwind CSS v4 (default) and v3 — pick your version in the install dialog
- Every color format — OKLCH, HSL, HEX, and RGB variants of every theme
- Built on CSS variables; compatible with shadcn/ui components
Themes ship in a full matrix of variants so they drop into any stack:
| OKLCH | HSL | HEX | RGB | |
|---|---|---|---|---|
| Tailwind v4 (default) | ✅ | ✅ | ✅ | ✅ |
| Tailwind v3 | — | ✅ | ✅ | ✅ |
- v4 variants use raw color values with
data-themeselectors and@theme inline(the modern shadcn architecture). The default install URL is v4 + OKLCH. - v3 variants emit bare channel triplets under
:root/.darkin@layer base, consumed viahsl(var(--token))(HSL) orrgb(var(--token))(HEX/RGB) in yourtailwind.config. OKLCH is not offered for v3 because the v3 wrapper model can't carry it.
In the theme picker, open a theme's Code dialog and use the Tailwind and Color format toggles to copy the exact variant (and its install command) you need.
Variant install URLs follow the pattern:
https://tweakcn-picker.vercel.app/r/theme-<name>-<v4|v3>-<hsl|hex|rgb>.json
# e.g. theme-catppuccin-v3-hsl.json (v4 + OKLCH is the default theme-<name>.json)
npx shadcn@latest add https://tweakcn-picker.vercel.app/r/nextjs/theme-system.jsonnpx shadcn@latest add https://tweakcn-picker.vercel.app/r/vite/theme-system.jsonnpx shadcn@latest add https://tweakcn-picker.vercel.app/r/astro/theme-system.jsonnpx shadcn@latest add https://tweakcn-picker.vercel.app/r/remix/theme-system.jsonAfter installing the theme system, add individual themes:
npx shadcn@latest add https://tweakcn-picker.vercel.app/r/theme-catppuccin.json
npx shadcn@latest add https://tweakcn-picker.vercel.app/r/theme-cyberpunk.json- Default
- Mocha Mousse
- Mono
- Modern Minimal
- Amber Minimal
- Clean Slate
- Catppuccin
- Bubblegum
- Nature
- Ocean Breeze
- Sunset Horizon
- Pastel Dreams
- Flora
- Perpetuity
- Tangerine
- Solar Dusk
- Candyland
- Northern Lights
- Claude
- Vercel
- T3 Chat
- Bold Tech
- Supabase
- Twitch
- Kick
- Spotify
- Stripe
- GitHub
- Cyberpunk
- Neo Brutalism
- Doom 64
- Kodama Grove
- Quantum Rose
- Elegant Luxury
- Claymorphism
- Retro Arcade
- Vintage Paper
- Windows 98
- Cosmic Night
- Midnight Bloom
- Graphite
- Caffeine
- Starry Night
Wrap your application with the ThemeProvider component. This must be placed at the root of your app.
// app/layout.tsx (Next.js) or main.tsx (Vite)
import { ThemeProvider } from "@/components/theme-provider";
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en" suppressHydrationWarning>
<body>
<ThemeProvider>{children}</ThemeProvider>
</body>
</html>
);
}The ThemeProvider is pre-configured with:
attribute="data-theme"- applies theme via data attributethemes={allThemeValues}- all available theme valuesdefaultTheme="default-dark"- default theme on first loadenableSystem={false}- system preference disabled (themes handle light/dark)disableTransitionOnChange- prevents flash during theme switch
A dropdown component for selecting themes and toggling light/dark mode.
import { ThemeSwitcher } from "@/components/theme-switcher";
export function Header() {
return (
<header>
<nav>{/* ... */}</nav>
<ThemeSwitcher />
</header>
);
}The switcher provides:
- Light/dark mode toggle
- Color theme selection with visual previews
- Current theme indicator
Access and control the theme programmatically using the useTheme hook from next-themes.
import { useTheme } from "next-themes";
export function MyComponent() {
const { theme, setTheme } = useTheme();
// Get current theme: "catppuccin-dark", "vercel-light", etc.
console.log(theme);
// Set theme directly
setTheme("cyberpunk-dark");
setTheme("nature-light");
return null;
}All themes follow the pattern {name}-{mode}:
{theme-name}-light // Light mode variant
{theme-name}-dark // Dark mode variant
Examples:
default-darkcatppuccin-lightcyberpunk-darkvercel-light
Each theme is defined with the following structure:
interface ThemeConfig {
name: string; // Theme identifier (e.g., "catppuccin")
title: string; // Display name (e.g., "Catppuccin")
primaryLight: string; // Primary color for light mode (oklch)
primaryDark: string; // Primary color for dark mode (oklch)
fontSans: string; // Font family
}The themes-config.ts file exports:
import {
themes, // Array of all ThemeConfig objects
sortedThemes, // Themes sorted alphabetically (default first)
themeNames, // Array of theme names: ["default", "catppuccin", ...]
allThemeValues, // All theme values: ["default-light", "default-dark", ...]
DEFAULT_THEME, // "default-dark"
} from "@/lib/themes-config";import { useTheme } from "next-themes";
import { themes } from "@/lib/themes-config";
export function CustomThemeSelector() {
const { theme, setTheme } = useTheme();
// Parse current theme
const currentName = theme?.replace(/-light$|-dark$/, "") || "default";
const isDark = theme?.endsWith("-dark") ?? true;
const toggleMode = () => {
setTheme(`${currentName}-${isDark ? "light" : "dark"}`);
};
const selectTheme = (name: string) => {
setTheme(`${name}-${isDark ? "dark" : "light"}`);
};
return (
<div>
<button onClick={toggleMode}>
{isDark ? "Switch to Light" : "Switch to Dark"}
</button>
<select value={currentName} onChange={(e) => selectTheme(e.target.value)}>
{themes.map((t) => (
<option key={t.name} value={t.name}>
{t.title}
</option>
))}
</select>
</div>
);
}registry/
themes/ # Canonical theme CSS (v4 + OKLCH) — the source of truth
variants/ # Generated v4/v3 × hsl/hex/rgb variants (do not edit by hand)
index.css # Generated import list
nextjs/ # Next.js adapter components
vite/ # Vite adapter components
astro/ # Astro adapter components
remix/ # Remix adapter components
scripts/
generate-themes.ts # Generator: canonical → all variants + registry items
lib/ # color conversion (culori) + lossless CSS parser
src/styles/ # Mirror of canonical themes for the demo site (generated)
public/r/ # Built registry JSON files
The canonical registry/themes/*.css files (Tailwind v4, OKLCH) are the single
source of truth. scripts/generate-themes.ts parses them losslessly and emits
every other variant, the src/styles mirror, index.css, and the variant
entries in registry.json. The generator guarantees the v4-OKLCH output is
byte-identical to the canonical files (parity gate), so regenerating never
drifts the originals.
Each theme defines shadow tokens (--shadow-2xs … --shadow-2xl, plus the
primitives --shadow-color, --shadow-opacity, --shadow-blur,
--shadow-spread, --shadow-offset-x/y). These drive shadcn's shadow-*
utilities so elevation is themeable. They're additive on top of the base shadcn
token set — safe to keep, and harmless if your project doesn't use them.
pnpm install
pnpm devRegenerate all theme variants (after editing a canonical theme or adding a new one):
pnpm themes:generateBuild the registry (runs the generator first, then shadcn build):
pnpm registry:buildMIT