Harumi

Colors

The color names a dashboard.toml accepts, where each one goes, and the full palette to pick from.

Charts are gray until you ask for a color

Every data-viz widget — chart, timeline, gantt-chart, treemap — renders in neutral grays by default, and those grays adapt to light and dark mode on their own. A color only appears when something in dashboard.toml asks for one.

That default is deliberate: a chart where every series is a different hue spends its color budget on decoration. Leaving colors unset and pinning only the one series that carries meaning ("late jobs are red") is what makes that one series read.

Asking the chat is usually faster than editing TOML

You don't have to write any of the TOML on this page by hand. On a project's dashboard, ask the chat by name — "make the cost chart green-600", or "blue-700 in light mode, blue-300 in dark". The names below are the vocabulary it understands; click any swatch to copy one.

A color is a Tailwind name, never a hex

Wherever dashboard.toml takes a color, it takes one of two things:

  • A name — <family>-<shade> (green-600, neutral-400), or black / white. Used as-is in both light and dark mode.
  • A { light, dark } pair of names — { light = "blue-700", dark = "blue-300" }. Each theme gets its own, so the color stays readable on either background.

A hex value ("#16a34a") is not accepted, and neither is a name that isn't in the palette below. There's no automatic light/dark flipping either — if you want a different shade per theme, say both.

An unrecognized color is skipped, not reported

A widget with an invalid color still renders: the bad value is dropped and that series or group falls back to the default gray, rather than the whole widget failing. So a typo'd name or a hex looks like "my color didn't apply", with nothing in the error banner. Check the name against the palette below if a color silently doesn't take effect.

Where a color goes

There are two places, and which one a widget offers depends on how it colors things.

series[].color — one color per series

chart draws one line, bar or area per entry in series (a legacy line-chart or bar-chart reads as a chart), so the color belongs to the entry:

[[widgets]]
type = "chart"
id = "cost-trend"
title = "Cost over time"
variant = "line"
data_key = "timeseries"
x_key = "label"
series = [
  { key = "cost", label = "Cost", color = "green-600" },
  { key = "budget", label = "Budget", color = { light = "neutral-500", dark = "neutral-400" } },
]

colors — pin specific groups

timeline, gantt-chart and treemap don't have a fixed list of series — they color by whatever distinct values show up in the field named by color_key. A colors table pins chosen values to chosen colors:

[[widgets]]
type = "timeline"
id = "schedule"
title = "Machine schedule"
items_key = "schedule"
color_key = "status"

[widgets.colors]
"Late job" = "red-600"
"Unassigned" = { light = "neutral-400", dark = "neutral-600" }

Every value you don't pin keeps cycling through the default grays — and the cycle skips any color a pin already claimed, so a pinned group and an auto-colored group are never handed the same color.

colors needs color_key

colors keys are matched against the raw values of the field color_key names, so a widget with no color_key has nothing to pin — every item is drawn from the palette cycle instead.

A chart takes colors too, keyed differently: a pie or donut matches its keys against each slice's x_key value, and a chart with group_key matches them against the group values, so you can pin the one slice or group that matters and leave the rest gray:

[[widgets]]
type = "chart"
id = "cost-share"
title = "Where the cost goes"
variant = "donut"
data_key = "cost_by_machine"
x_key = "machine"
series = [{ key = "cost", label = "Cost" }]

[widgets.colors]
"Machine 3" = "red-600"

The default grays

With nothing pinned, groups are assigned these six in order of first appearance. Each is a light/dark pair, which is why a default chart keeps its contrast when you switch themes:

#Light modeDark mode
1
neutral-800
neutral-200
2
neutral-500
neutral-500
3
neutral-700
neutral-300
4
neutral-400
neutral-600
5
neutral-900
neutral-100
6
neutral-600
neutral-400

Six entries means a widget with more than six distinct groups starts repeating grays. Pin colors past that point if the repetition is confusing.

The full palette

Every name below is valid anywhere dashboard.toml takes a color — 26 families at 11 shades each (50 through 950), plus black and white. Click a swatch to copy its name, then paste it into the chat or your TOML.

50100200300400500600700800900950
slate
gray
zinc
neutral
stone
mauve
olive
mist
taupe
red
orange
amber
yellow
lime
green
emerald
teal
cyan
sky
blue
indigo
violet
purple
fuchsia
pink
rose
black
white

Checking a color before you commit

harumi dashboard validate checks a real dashboard.toml, including the structure of a series entry and a colors table. Since an unrecognized color is dropped rather than raised, the surest check on the color itself is the name: it must appear in the palette above, exactly as spelled there.

On this page