Theming
Colors
Customize colors across your Gridland UI components with built-in themes or your own custom theme.
Gridland UI uses semantic color tokens to theme all components. A Theme is a flat object of 17 hex values covering brand, content, borders, status, focus indicators, and message bubbles.
Without a ThemeProvider, all components fall back to the built-in dark theme.
Theming
Quick Start
import { ThemeProvider, darkTheme } from "@/lib/theme"
import { Spinner } from "@/components/ui/spinner"
import { Table } from "@/components/ui/table"
function App() {
return (
<ThemeProvider theme={darkTheme}>
<Spinner text="Loading..." />
<Table data={[{ name: "Alice", role: "Admin" }]} />
</ThemeProvider>
)
}Tokens
Brand
| Token | Purpose |
|---|---|
primary | Main brand color headings, highlights, active elements |
accent | Secondary brand color interactive highlights, focused states |
secondary | Tertiary color user messages, checkboxes, prompts |
Content
| Token | Purpose |
|---|---|
foreground | Default foreground text color |
background | App background color |
muted | Subdued color disabled states, secondary text, cursor |
placeholder | Placeholder text in inputs |
Borders
| Token | Purpose |
|---|---|
border | Borders and dividers |
borderMuted | Muted border color subtle structural dividers |
Status
| Token | Purpose |
|---|---|
success | Success state color |
error | Error state color |
warning | Warning state color |
Focus
Three-tier focus system (see Focus for the full model):
| Token | Purpose |
|---|---|
focusSelected | Bright focus component is selected (entered for interaction) |
focusFocused | Medium focus component has keyboard focus |
focusIdle | Dimmed focus idle hint that the component is selectable |
Messages
| Token | Purpose |
|---|---|
messageAssistant | Background color for assistant message bubbles |
messageUser | Background color for user message bubbles |
Built-in Themes
import { darkTheme, lightTheme } from "@/lib/theme"Dark
#FF71CE
primary#01CDFE
accent#B967FF
secondary#A69CBD
muted#CEC7DE
placeholder#B967FF
border#2A2A2A
borderMuted#F0E6FF
foreground#0D0B10
background#05FFA1
success#FF6B6B
error#FFC164
warning#FF71CE
focusSelected#e065b8
focusFocused#33192a
focusIdle#2a2a4a
messageAssistant#2a3a3a
messageUserLight
#FF6B2B
primary#3B82F6
accent#0369A1
secondary#64748B
muted#475569
placeholder#E2E8F0
border#D9D9D9
borderMuted#1E293B
foreground#FFFFFF
background#0B8438
success#E11D48
error#B45309
warning#FF6B2B
focusSelected#d45a24
focusFocused#f5e6d8
focusIdle#F1F5F9
messageAssistant#E2E8F0
messageUserCustom Themes
import type { Theme } from "@/lib/theme"
export const myTheme: Theme = {
// Brand
primary: "#61afef",
accent: "#c678dd",
secondary: "#98c379",
// Content
foreground: "#abb2bf",
background: "#282c34",
muted: "#5c6370",
placeholder: "#4b5263",
// Borders
border: "#5c6370",
borderMuted: "#3e4451",
// Status
success: "#98c379",
error: "#e06c75",
warning: "#e5c07b",
// Focus (bright → dim)
focusSelected: "#61afef",
focusFocused: "#4b8dc9",
focusIdle: "#2c3e50",
// Message bubbles
messageAssistant: "#2c313a",
messageUser: "#3a3f4b",
}Or extend a built-in theme:
import { darkTheme } from "@/lib/theme"
export const customTheme = {
...darkTheme,
primary: "#61afef",
}useTheme
Access tokens in your own components:
import { useTheme } from "@/lib/theme"
function MyComponent() {
const theme = useTheme()
return <text style={{ fg: theme.primary }}>Themed text</text>
}Explicit color props always override theme values:
<Spinner text="Default" /> {/* uses theme.accent */}
<Spinner text="Custom" color="#FF6B6B" /> {/* overrides theme */}