Interactive playground
Theme Kit Playground
Everything below runs on Theme Kit's real runtime — the same store, history, and resolver that ships in the library. Switch a family or mode, explore the token tree, audit contrast, run a transition, and watch CSS variables update live.
Live theme switcher
Family controls the palette, mode controls light/dark/system.
Theme Scope
Sandbox any subtree with its own theme — independent of the global runtime.
Component-Scoped Themes
Each card below uses a different scoped theme, independent of the global theme.
This card always uses the forest color palette regardless of the global theme.
This card always uses the plum color palette regardless of the global theme.
This card follows the global theme and changes when you toggle.
Live preview
theme-kit · systemHistory & time travel
Every theme change is recorded as a snapshot. Click any entry to jump to that point in time.
1 snapshot · capped at 50 · theme-kit-default-light is current
Interactive token tree
Expand a group, search a token, or hover a value to copy its CSS variable.
- colors21
- background
- foreground
- card
- cardForeground
- popover
- popoverForeground
- primary
- primaryForeground
- secondary
- secondaryForeground
- muted
- mutedForeground
- accent
- accentForeground
- destructive
- destructiveForeground
- success
- successForeground
- border
- input
- ring
- radius1
- lg12px
- code19
- background#f6f7fc
- foreground#0f172a
- comment#6b7280
- keyword#7c3aed
- string#07865c
- number#d97706
- function#2563eb
- variable#0f172a
- type#db2777
- property#0284c7
- operator#7c3aed
- punctuation#475569
- tag#be185d
- attribute#0284c7
- lineNumber#9ca3af
- selectionrgba(91, 84, 232, 0.12)
- highlightrgba(91, 84, 232, 0.06)
- gutter#f6f7fc
- border#e4e6f2
3 token groups · values are the resolved runtime tokens for the active theme.
Multi-window sync
Theme selections sync across tabs and windows in real time via BroadcastChannel (with SharedWorker and StorageEvent fallbacks).
Changes made here flow over the channel to every real tab open on this site — exactly what a second browser tab would do.
No cross-tab sync method is available in this browser.
Scheduled themes · solar time
Run the real useThemeSchedule() controller: enable the schedule to flip the whole site between light and dark at sunrise/sunset. Leave it on Auto to use your own detected timezone — no coordinates needed — or pick any timezone in the world and watch the sun path follow it. See the Sunrise & Sunset page for per-framework setup.
This runs the real useThemeSchedule() controller against the site runtime, switching the whole page between light and dark at sunrise/sunset. With Auto selected, your own timezone is detected — no coordinates needed, anywhere in the world. Pick a timezone below to reposition the schedule, or drag the lat/lon sliders for a manual preview.
Theme Kit computes NOAA-style solar times via calculateSunTimes(date, lat, lon) — with no coordinates it auto-detects the visitor's timezone — and can auto-switch between light and dark at sunrise/sunset with the scheduled runtime option. Current site mode: system.
Theme generator
Generate a complete light/dark theme pair from a seed color, then copy the JSON or CSS variables.
Theme generator
Pick a seed color and generate a matching light/dark theme pair. Optional syntax-highlighting code tokens are generated on request.
Animation & transition lab
Run the real transition pipeline — createThemeDiff, createTransitionPlan and runThemeAnimation — and tune duration, easing and presets live.
createScopedThemeBinding — runs its own transition while the rest of the page is untouched.Scoped subtree runs the real theme-kit animation pipeline (createThemeDiff→createTransitionPlan→runThemeAnimation). Its transition timeline is independent of the page-level theme.
Custom scrollbar
The real overlay engine, integrated on this site — scroll the panel to see the theme-colored strip replace the native bar. For per-framework setup, see Custom Scrollbar.
This panel is a plain scrollable container, exactly like the one you would wrap in include to scope the overlay. On this site the real ThemeScrollbar from @theme-kit/next is mounted in the root layout — so every scrollable area on this page, including this one, is an integrated custom scrollbar. Run your cursor over the edge to reveal the theme-colored strip, then scroll.
Managed container — row 1. The native bar is hidden by the pre-paint bootstrap and the overlay strip represents the scroll position instead.
Managed container — row 2. The native bar is hidden by the pre-paint bootstrap and the overlay strip represents the scroll position instead.
Managed container — row 3. The native bar is hidden by the pre-paint bootstrap and the overlay strip represents the scroll position instead.
Managed container — row 4. The native bar is hidden by the pre-paint bootstrap and the overlay strip represents the scroll position instead.
Managed container — row 5. The native bar is hidden by the pre-paint bootstrap and the overlay strip represents the scroll position instead.
Managed container — row 6. The native bar is hidden by the pre-paint bootstrap and the overlay strip represents the scroll position instead.
Managed container — row 7. The native bar is hidden by the pre-paint bootstrap and the overlay strip represents the scroll position instead.
Managed container — row 8. The native bar is hidden by the pre-paint bootstrap and the overlay strip represents the scroll position instead.
Managed container — row 9. The native bar is hidden by the pre-paint bootstrap and the overlay strip represents the scroll position instead.
Managed container — row 10. The native bar is hidden by the pre-paint bootstrap and the overlay strip represents the scroll position instead.
Managed container — row 11. The native bar is hidden by the pre-paint bootstrap and the overlay strip represents the scroll position instead.
Managed container — row 12. The native bar is hidden by the pre-paint bootstrap and the overlay strip represents the scroll position instead.
Managed container — row 13. The native bar is hidden by the pre-paint bootstrap and the overlay strip represents the scroll position instead.
Managed container — row 14. The native bar is hidden by the pre-paint bootstrap and the overlay strip represents the scroll position instead.
Accessibility lab
Check WCAG contrast on any pair, simulate color-vision deficiency, and audit the active theme's semantic pairs.
Contrast checker
Pick any two colors and check WCAG AA/AAA compliance instantly.
This pair passes AA for normal text.
Live theme audit · theme-kit-default-light
validateThemeContrast() run against the active theme's semantic pairs.
foreground on backgroundcardForeground on cardpopoverForeground on popoverprimaryForeground on primarysecondaryForeground on secondarymutedForeground on mutedaccentForeground on accentdestructiveForeground on destructiveColor vision deficiency simulation
simulateCVD() of the active primary (#5b54e8).
Re-themes the site with every color run through simulateThemeForCVD() so you can check readability exactly as a user with that condition sees it.
Accessibility profiles
Ready-made high-contrast and large-text themes shipped in getBuiltInThemes().
Maximum contrast for readability.
Maximum contrast on dark backgrounds.
Enlarged type on light backgrounds.
Enlarged type on dark backgrounds.
The accessibility plugin — reacting to violations
createAccessibilityPlugin() audits every applied theme at WCAG AA and fires onViolation when a theme breaks the configured requirements. This is that callback, live.
Try it: a “low-contrast-demo” theme (white foreground on white background) is handed to the plugin's onAfterThemeChange hook — exactly what happens when such a theme is applied to a runtime.
Theme studio
Generate a full light/dark pair from a seed with generateTheme(), preview it, and apply it to this site live.
1{
2 "light": {
3 "name": "indigo-light",
4 "meta": {
5 "family": "indigo",
6 "mode": "light",
7 "label": "Indigo Light",
8 "order": 10
9 },
10 "tokens": {
11 "colors": {
12 "background": "#f8fafc",
13 "foreground": "#0f172a",
14 "card": "#ffffff",
15 "cardForeground": "#0f172a",
16 "popover": "#ffffff",
17 "popoverForeground": "#0f172a",
18 "primary": "#6366f1",
19 "primaryForeground": "#ffffff",
20 "secondary": "#e4e4f1",
21 "secondaryForeground": "#0f172a",
22 "muted": "#efeff5",
23 "mutedForeground": "#64748b",
24 "accent": "#c6c6ec",
25 "accentForeground": "#0f172a",
26 "destructive": "#ef4444",
27 "destructiveForeground": "#ffffff",
28 "success": "#22c55e",
29 "successForeground": "#ffffff",
30 "border": "#d9d9e8",
31 "input": "#d9d9e8",
32 "ring": "#6366f1"
33 },
34 "radius": {
35 "lg": "8px"
36 }
37 }
38 },
39 "dark": {
40 "name": "indigo-dark",
41 "meta": {
42 "family": "indigo",
43 "mode": "dark",
44 "label": "Indigo Dark",
45 "order": 20
46 },
47 "tokens": {
48 "colors": {
49 "background": "#020617",
50 "foreground": "#f8fafc",
51 "card": "#0f172a",
52 "cardForeground": "#f8fafc",
53 "popover": "#0f172a",
54 "popoverForeground": "#f8fafc",
55 "primary": "#9596ea",
56 "primaryForeground": "#020617",
57 "secondary": "#060846",
58 "secondaryForeground": "#f8fafc",
59 "muted": "#050638",
60 "mutedForeground": "#94a3b8",
61 "accent": "#151651",
62 "accentForeground": "#f8fafc",
63 "destructive": "#f87171",
64 "destructiveForeground": "#020617",
65 "success": "#4ade80",
66 "successForeground": "#020617",
67 "border": "#080a5e",
68 "input": "#080a5e",
69 "ring": "#9596ea"
70 },
71 "radius": {
72 "lg": "8px"
73 }
74 }
75 }
76}