Theming
Kaeyros UI uses CSS variables for theming. Change a few HSL values in app/globals.css to rebrand the entire library — light mode, dark mode, focus rings, borders, all of it.
Quick start
Add these blocks to your app/globals.css:
css@tailwind base;
@tailwind components;
@tailwind utilities;
@layer base {
:root {
--background: 0 0% 100%;
--foreground: 240 10% 3.9%;
--card: 0 0% 100%;
--card-foreground: 240 10% 3.9%;
--primary: 240 5.9% 10%;
--primary-foreground: 0 0% 98%;
--muted: 240 4.8% 95.9%;
--muted-foreground: 240 3.8% 46.1%;
--border: 240 5.9% 90%;
--ring: 240 5.9% 10%;
--radius: 0.5rem;
}
.dark {
--background: 240 10% 3.9%;
--foreground: 0 0% 98%;
--card: 240 10% 3.9%;
--card-foreground: 0 0% 98%;
--primary: 0 0% 98%;
--primary-foreground: 240 5.9% 10%;
--muted: 240 3.7% 15.9%;
--muted-foreground: 240 5% 64.9%;
--border: 240 3.7% 15.9%;
--ring: 240 4.9% 83.9%;
}
}Note: CSS-variable values use the HSL channels (no hsl() wrapper). Tailwind wraps them automatically via hsl(var(--primary)) in the config.
Color presets
Pick a preset and replace the --primary values in :root:
Slate (default)
--primary: 240 5.9% 10%;
--primary-foreground: 0 0% 98%;Blue
--primary: 221.2 83.2% 53.3%;
--primary-foreground: 210 40% 98%;Violet
--primary: 262.1 83.3% 57.8%;
--primary-foreground: 210 20% 98%;Emerald
--primary: 142.1 76.2% 36.3%;
--primary-foreground: 355.7 100% 97.3%;Rose
--primary: 346.8 77.2% 49.8%;
--primary-foreground: 355.7 100% 97.3%;Amber
--primary: 32.1 94.6% 43.7%;
--primary-foreground: 60 9.1% 97.8%;All CSS variables
| Variable | Purpose | Light | Dark |
|---|---|---|---|
--background | Page background | 0 0% 100% | 240 10% 3.9% |
--foreground | Default text color | 240 10% 3.9% | 0 0% 98% |
--card | Card / surface background | 0 0% 100% | 240 10% 3.9% |
--card-foreground | Text on card surfaces | 240 10% 3.9% | 0 0% 98% |
--popover | Popover / dropdown background | 0 0% 100% | 240 10% 3.9% |
--popover-foreground | Text on popovers | 240 10% 3.9% | 0 0% 98% |
--primary | Primary brand color | 240 5.9% 10% | 0 0% 98% |
--primary-foreground | Text on primary surfaces | 0 0% 98% | 240 5.9% 10% |
--secondary | Secondary surfaces | 240 4.8% 95.9% | 240 3.7% 15.9% |
--secondary-foreground | Text on secondary | 240 5.9% 10% | 0 0% 98% |
--muted | Muted backgrounds (skeleton, hover) | 240 4.8% 95.9% | 240 3.7% 15.9% |
--muted-foreground | Muted text (descriptions, hints) | 240 3.8% 46.1% | 240 5% 64.9% |
--accent | Accent (hover states) | 240 4.8% 95.9% | 240 3.7% 15.9% |
--accent-foreground | Text on accent | 240 5.9% 10% | 0 0% 98% |
--destructive | Destructive / danger | 0 72% 51% | 0 62.8% 30.6% |
--destructive-foreground | Text on destructive | 0 0% 98% | 0 0% 98% |
--border | Default border color | 240 5.9% 90% | 240 3.7% 15.9% |
--input | Input border color | 240 5.9% 90% | 240 3.7% 15.9% |
--ring | Focus ring color | 240 5.9% 10% | 240 4.9% 83.9% |
--radius | Default border radius | 0.5rem | 0.5rem |
Dark mode
Kaeyros UI uses Tailwind's class dark mode strategy. Toggle the .dark class on <html> to switch.
Recommended: use next-themes for system preference + persisted choice.
tsx// app/layout.tsx
import { ThemeProvider } from 'next-themes'
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en" suppressHydrationWarning>
<body>
<ThemeProvider attribute="class" defaultTheme="system" enableSystem>
{children}
</ThemeProvider>
</body>
</html>
)
}tsx// Theme toggle button
'use client'
import { useTheme } from 'next-themes'
import { Sun, Moon } from 'lucide-react'
export function ThemeToggle() {
const { theme, setTheme } = useTheme()
return (
<button onClick={() => setTheme(theme === 'dark' ? 'light' : 'dark')}>
{theme === 'dark' ? <Sun /> : <Moon />}
</button>
)
}Wiring CSS variables to Tailwind
In your tailwind.config.ts:
ts// tailwind.config.ts
import type { Config } from 'tailwindcss'
const config: Config = {
darkMode: ['class'],
content: ['./app/**/*.{ts,tsx}', './components/**/*.{ts,tsx}'],
theme: {
extend: {
colors: {
border: 'hsl(var(--border))',
input: 'hsl(var(--input))',
ring: 'hsl(var(--ring))',
background: 'hsl(var(--background))',
foreground: 'hsl(var(--foreground))',
primary: {
DEFAULT: 'hsl(var(--primary))',
foreground: 'hsl(var(--primary-foreground))',
},
secondary: {
DEFAULT: 'hsl(var(--secondary))',
foreground: 'hsl(var(--secondary-foreground))',
},
destructive: {
DEFAULT: 'hsl(var(--destructive))',
foreground: 'hsl(var(--destructive-foreground))',
},
muted: {
DEFAULT: 'hsl(var(--muted))',
foreground: 'hsl(var(--muted-foreground))',
},
accent: {
DEFAULT: 'hsl(var(--accent))',
foreground: 'hsl(var(--accent-foreground))',
},
popover: {
DEFAULT: 'hsl(var(--popover))',
foreground: 'hsl(var(--popover-foreground))',
},
card: {
DEFAULT: 'hsl(var(--card))',
foreground: 'hsl(var(--card-foreground))',
},
},
borderRadius: {
lg: 'var(--radius)',
md: 'calc(var(--radius) - 2px)',
sm: 'calc(var(--radius) - 4px)',
},
},
},
}
export default configSeverity colors
The Kaeyros button (and many other components) uses 8 semantic severity colors mapped to Tailwind palettes — they aren't CSS variables but live directly in the component:
primary
severity
secondary
severity
success
severity
info
severity
warning
severity
help
severity
danger
severity
contrast
severity
To rebrand these, edit the sevColors object inside components/kaeyros/button.tsx.