Get-Started
Get Started
One core, one mental model, every framework. Pick your stack and follow the five steps to a live themed app.
How are you building?
The concepts stay identical across every stack — only the wiring changes. The core is one package; your framework adds an adapter.
Selected: Next.js — installing @theme-kit/next alongside @theme-kit/core.
Install
Theme Kit is two packages: the framework-agnostic @theme-kit/core containing themes, tokens and the runtime, plus a thin @theme-kit/next adapter.
pnpm add @theme-kit/core @theme-kit/nextDefine your theme
A theme is defined with defineTheme: a name, optional metadata (family, mode, label), and a nested tokens object. Keep one entry per family × mode combo.
The exported themes array is what you import into your provider in the next step — import { themes } from "./themes".
1// themes.ts
2import { defineTheme } from "@theme-kit/core";
3
4export const themes = [
5 defineTheme({
6 name: "mint-light",
7 meta: { family: "mint", mode: "light", label: "Mint Light" },
8 tokens: {
9 colors: {
10 background: "#fafcf8",
11 foreground: "#17211a",
12 card: "#ffffff",
13 primary: "#3f9d63",
14 primaryForeground: "#ffffff",
15 secondary: "#ecf3ec",
16 accent: "#d9ecde",
17 muted: "#f1f5ef",
18 mutedForeground: "#64706a",
19 destructive: "#dc2626",
20 destructiveForeground: "#ffffff",
21 success: "#16a34a",
22 successForeground: "#ffffff",
23 border: "#e2e8e2",
24 input: "#e2e8e2",
25 ring: "#3f9d63",
26 },
27 radius: { lg: "12px" },
28 },
29 }),
30 defineTheme({
31 name: "mint-dark",
32 meta: { family: "mint", mode: "dark", label: "Mint Dark" },
33 tokens: {
34 colors: {
35 background: "#0d1210",
36 foreground: "#e8f1ea",
37 card: "#141b17",
38 primary: "#4cb377",
39 primaryForeground: "#0d1210",
40 secondary: "#1a231d",
41 accent: "#1d2d22",
42 muted: "#161f1a",
43 mutedForeground: "#93a39a",
44 destructive: "#f87171",
45 destructiveForeground: "#0d1210",
46 success: "#4ade80",
47 successForeground: "#0d1210",
48 border: "#263229",
49 input: "#263229",
50 ring: "#4cb377",
51 },
52 radius: { lg: "12px" },
53 },
54 }),
55];The snippet above sets meta.mode explicitly. That's the recommended form, but you can also define themes without it — the mode is then inferred from the theme name:
1// themes.ts — meta.mode is optional; the mode is inferred from the name.
2// Families: themes without meta.family belong to the "default" family.
3export const themes = [
4 { name: "light", tokens: { colors: { background: "#ffffff", primary: "#6366f1" } } },
5 { name: "dark", tokens: { colors: { background: "#0a0a0a", primary: "#818cf8" } } },
6];Both forms support setMode("dark") and toggleTheme() the same way. The meta.family field groups themes into families; without it every theme belongs to the default family.
Add the Next.js provider
Wrap your app at the entry point — app/layout.tsx — and pass your themes. Persistence, hydration and bootstrapping are wired for you.
Provider is @theme-kit/next (installed in step 1). See the Next.js guide or the package map for the full reference.
1// app/layout.tsx
2import { ThemeProvider } from "@theme-kit/next";
3import { themes } from "./theme/themes";
4
5export default function RootLayout({ children }) {
6 return (
7 <ThemeProvider
8 themes={themes}
9 defaultTheme="mint-light"
10 >
11 {children}
12 </ThemeProvider>
13 );
14}Use the theme
Read the active theme and switch it from any component. This is the same example your Next.js guide covers in depth.
1// app/layout.tsx
2import { ThemeProvider } from "@theme-kit/next";
3import { themes } from "./theme/themes";
4
5export default function RootLayout({ children }) {
6 return (
7 <ThemeProvider themes={themes} defaultTheme="mint-light">
8 {children}
9 </ThemeProvider>
10 );
11}
12
13// components/ThemeSwitcher.tsx
14"use client";
15import { useTheme } from "@theme-kit/next/client";Customize
Real example from the Next.js docs (layout + theme-switcher) — then go deeper into tokens, scoping and the runtime.
1// app/layout.tsx
2import { ThemeProvider } from "@theme-kit/next";
3
4export default function RootLayout({ children }) {
5 return (
6 <ThemeProvider themes={themes} defaultTheme="mint-light"> {/* mint-light | mint-dark | light | dark | system */}
7 {children}
8 </ThemeProvider>
9 );
10}
11
12// app/theme-switcher.tsx
13"use client";
14import { useTheme } from "@theme-kit/next/client";
15
16export function ThemeSwitcher() {
17 const { theme, mode, setMode, toggleTheme } = useTheme();
18 return (
19 <div>
20 <button onClick={toggleTheme}>{theme.name} · {mode}</button>
21 <button onClick={() => setMode("dark")}>Dark</button>
22 <button onClick={() => setMode("light")}>Light</button>
23 </div>
24 );
25}Your first Theme Kit application
Five minutes in — this is a real demo running the same runtime the docs use. The card below is built entirely from semantic tokens.
One setMode() call — everything on this screen follows.
Try changing:
You're ready.
What you just set up is the full theming system — families, tokens, persistence and history. Stretch it next in the playground or the Theme Studio.