gridland
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

app.tsx
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

TokenPurpose
primaryMain brand color headings, highlights, active elements
accentSecondary brand color interactive highlights, focused states
secondaryTertiary color user messages, checkboxes, prompts

Content

TokenPurpose
foregroundDefault foreground text color
backgroundApp background color
mutedSubdued color disabled states, secondary text, cursor
placeholderPlaceholder text in inputs

Borders

TokenPurpose
borderBorders and dividers
borderMutedMuted border color subtle structural dividers

Status

TokenPurpose
successSuccess state color
errorError state color
warningWarning state color

Focus

Three-tier focus system (see Focus for the full model):

TokenPurpose
focusSelectedBright focus component is selected (entered for interaction)
focusFocusedMedium focus component has keyboard focus
focusIdleDimmed focus idle hint that the component is selectable

Messages

TokenPurpose
messageAssistantBackground color for assistant message bubbles
messageUserBackground 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
messageUser

Light

#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
messageUser

Custom Themes

my-theme.ts
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:

custom-theme.ts
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 */}