Documentation Index
Fetch the complete documentation index at: https://mintlify.com/BankkRoll/tweakcn-theme-picker/llms.txt
Use this file to discover all available pages before exploring further.
Prerequisites
Before installing themes, ensure you have shadcn/ui set up in your Vite React project. If you haven’t already:
Install required components
The theme system requires these shadcn/ui components:npx shadcn@latest add dropdown-menu scroll-area button
Installation
Install the theme system
Install the complete theme system with all 40+ themes:npx shadcn@latest add https://tweakcn-picker.vercel.app/r/vite/theme-system
This installs:
lib/themes-config.ts - Theme configuration and metadata
components/theme-provider.tsx - Custom React theme provider
components/theme-switcher.tsx - Interactive theme switcher UI
styles/themes/*.css - All 40+ theme CSS files
Add ThemeProvider to your app root
Wrap your application with the ThemeProvider in src/App.tsx:import { ThemeProvider } from "@/components/theme-provider";
import "@/styles/themes/index.css";
function App() {
return (
<ThemeProvider>
{/* Your app content */}
</ThemeProvider>
);
}
export default App;
Add the ThemeSwitcher to your UI
Import and use the ThemeSwitcher component anywhere in your app:src/components/Header.tsx
import { ThemeSwitcher } from "@/components/theme-switcher";
export function Header() {
return (
<header>
<nav>
{/* Your navigation */}
<ThemeSwitcher />
</nav>
</header>
);
}
How it works
The Vite adapter uses a custom theme provider with localStorage persistence:
Theme Provider implementation
Located at components/theme-provider.tsx:import { createContext, useContext, useEffect, useState } from "react";
import { allThemeValues, DEFAULT_THEME } from "@/lib/themes-config";
type ThemeProviderState = {
theme: string;
setTheme: (theme: string) => void;
};
const ThemeProviderContext = createContext<ThemeProviderState>({
theme: DEFAULT_THEME,
setTheme: () => null,
});
export function ThemeProvider({
children,
defaultTheme = DEFAULT_THEME,
storageKey = "tweakcn-theme",
}: {
children: React.ReactNode;
defaultTheme?: string;
storageKey?: string;
}) {
const [theme, setTheme] = useState<string>(
() => localStorage.getItem(storageKey) || defaultTheme,
);
useEffect(() => {
const root = window.document.documentElement;
root.setAttribute("data-theme", theme);
}, [theme]);
const value = {
theme,
setTheme: (theme: string) => {
localStorage.setItem(storageKey, theme);
setTheme(theme);
},
};
return (
<ThemeProviderContext.Provider value={value}>
{children}
</ThemeProviderContext.Provider>
);
}
export const useTheme = () => {
const context = useContext(ThemeProviderContext);
if (context === undefined)
throw new Error("useTheme must be used within a ThemeProvider");
return context;
};
The provider manages theme state and automatically updates the data-theme attribute on the document root.
All theme metadata is in lib/themes-config.ts:export interface ThemeConfig {
name: string; // e.g., "catppuccin"
title: string; // Display name
primaryLight: string; // Primary color in light mode
primaryDark: string; // Primary color in dark mode
fontSans: string; // Font family
}
export const themes: ThemeConfig[] = [
{
name: "vercel",
title: "Vercel",
primaryLight: "oklch(0 0 0)",
primaryDark: "oklch(1 0 0)",
fontSans: "Geist, sans-serif",
},
// ... 40+ more themes
];
// Generate all theme values (name-light and name-dark)
export const allThemeValues = themes.flatMap((t) => [
`${t.name}-light`,
`${t.name}-dark`,
]);
Themes are automatically saved to localStorage with the key tweakcn-theme:const setTheme = (theme: string) => {
localStorage.setItem(storageKey, theme);
setTheme(theme);
};
On page load, the theme is restored from localStorage:const [theme, setTheme] = useState<string>(
() => localStorage.getItem(storageKey) || defaultTheme,
);
Adding individual themes
To install specific themes instead of all 40+:
npx shadcn@latest add https://tweakcn-picker.vercel.app/r/theme-vercel
Then import only the themes you need:
src/styles/themes/index.css
@import "./vercel.css";
@import "./github.css";
@import "./stripe.css";
Customizing themes
All theme CSS files are in src/styles/themes/. Each theme defines CSS variables:
src/styles/themes/vercel.css
[data-theme="vercel-light"] {
--background: oklch(1 0 0);
--foreground: oklch(0 0 0);
--primary: oklch(0 0 0);
--primary-foreground: oklch(1 0 0);
/* ... more variables */
}
[data-theme="vercel-dark"] {
--background: oklch(0 0 0);
--foreground: oklch(1 0 0);
--primary: oklch(1 0 0);
--primary-foreground: oklch(0 0 0);
/* ... more variables */
}
Edit these files to customize colors, borders, shadows, and more.
TypeScript usage
Use the useTheme hook from the theme provider:
import { useTheme } from "@/components/theme-provider";
function MyComponent() {
const { theme, setTheme } = useTheme();
return (
<div>
<p>Current theme: {theme}</p>
<button onClick={() => setTheme("vercel-dark")}>
Switch to Vercel Dark
</button>
<button onClick={() => setTheme("github-light")}>
Switch to GitHub Light
</button>
</div>
);
}
Vite configuration
Ensure your vite.config.ts has path aliases configured:
import path from "path";
import react from "@vitejs/plugin-react";
import { defineConfig } from "vite";
export default defineConfig({
plugins: [react()],
resolve: {
alias: {
"@": path.resolve(__dirname, "./src"),
},
},
});
Next steps
Browse Themes
Explore all 40+ available themes
Theme Picker
Preview themes in real-time
Next.js Setup
Install themes in Next.js
Remix Setup
Install themes in Remix