Colors

Koala's color system is three layers deep: a literal value, the CSS variable that holds it, and the semantic token a component writes. Components only ever reach for the top layer.

Three layers#

It helps to keep three things apart. A literal value is a raw, theme-blind color (#F84416, oklch(1 0 0)). A CSS variable (--background, --primary) holds one literal per theme. A semantic token is the utility a component writes (bg-background, text-foreground). It resolves to the variable, never to a literal. Change a theme by swapping the variables; the literals move, the tokens stay put.

the chain, bottom to topCSS
/* 1: literal value (raw, theme-blind) */oklch(0.205 0 0)/* 2: CSS variable, one literal per theme */:root  { --primary: oklch(0.205 0 0); }   /* light */.dark  { --primary: oklch(0.922 0 0); }   /* dark  *//* 3: semantic token, what a component writes */@theme inline { --color-primary: var(--primary); }.button { background: var(--color-primary); }  /* bg-primary */

The swatches below document the token and variable layers, the part you build with. The literal colors at the bottom are the raw escape hatch. For changing the variables, see Theming.

Surfaces#

Each swatch shows the token a component writes and, below it, the CSS variable it resolves to.

Backgrounds & surfaces

bg-background

--background

App background

bg-canvas

--canvas

App shell frame: black in light themes, the ground in dark ones

bg-card

--card

Cards, raised panels

bg-popover

--popover

Popovers, menus

bg-muted

--muted

Subtle fills

bg-secondary

--secondary

Secondary fills

bg-accent

--accent

Hover / active accent

Content#

Text & foreground

text-foreground

--foreground

Primary text

text-body

--body

Reading copy: ledes, quotes, answers

text-muted-foreground

--muted-foreground

Meta: captions, roles, dates

text-card-foreground

--card-foreground

Text on cards

Inline text links use one role, text-link, derived from --brand so a link carries the active accent. It stays its own role because it is tuned for text where --brand is tuned for fills: the raw accent only reaches 3.6:1 as text on white, so the light theme darkens it to clear the 4.5:1 AA floor while the dark themes use it straight. Keep it distinct from text-info, which is a status hue and never a link. Links carry a hairline underline at rest and turn both the text and the underline text-link on hover. Do not hand-roll that treatment: use <Link variant="prose">.

Links

text-link

--link

Inline text links (the accent, darkened for text on light)

Brand & state#

Actions

bg-primary

--primary

Primary actions

bg-secondary

--secondary

Secondary actions

bg-brand

--brand

Accent, set via data-accent

text-brand-foreground

--brand-foreground

Ink on a brand fill (white, dark on lime)

bg-destructive

--destructive

Destructive / error

Status#

Status roles read at full strength for text and icons; soft badges derive their tint from the same role via opacity (bg-success/10 + text-success).

Feedback roles

bg-success

--success

Success / positive

bg-warning

--warning

Warning / caution

bg-info

--info

Informational

bg-destructive

--destructive

Error / danger

Categorical hues#

A small, fixed set of distinct hues for labels, tags and category badges. Use these when items need to be told apart, not ranked.

Label & tag hues

bg-purple

--purple

bg-pink

--pink

bg-teal

--teal

bg-orange

--orange

Lines & focus#

Borders & rings

border-border

--border

Default borders

border-input

--input

Form field borders

ring-ring

--ring

Focus rings

Literal colors#

The bottom layer: raw values that do not respond to theming. Koala authors these in oklch for a wider, more even gamut, but any color-mix()-friendly literal works, including plain hex. Reach for a literal only when a color must stay fixed across every theme (a logo, a chart series, a brand mark). For anything that should restyle, use a semantic token above.

The brand accent (default)

#F84416

Hex: the default Koala accent

oklch(0.648 0.222 34.2)

The same color, as authored

Tailwind v4’s entire oklch palette ships out of the box: 22 families × 11 shades, each a bg-* / text-* / border-* utility (bg-blue-500, text-rose-600, …). Every chip below is a fixed literal; hover one to read its family-shade name and oklch value.

50100200300400500600700800900950
red
orange
amber
yellow
lime
green
emerald
teal
cyan
sky
blue
indigo
violet
purple
fuchsia
pink
rose
slate
gray
zinc
neutral
stone

Rule of thumb: if it should change when the theme changes, it is a token: reach for a role above. If it must stay exactly that color forever, it is a literal.