Color

The semantic color tokens every BoardUI component is built from - foreground, text, background, and border roles, named 1:1 with the Figma variables.

How the system works

Colors are layered in two tiers. Primitives are the raw palette - Tailwind's default OKLCH scales plus a handful of Figma-tuned overrides in styles/theme.css. Semantic tokens sit on top and reference those primitives by purpose - what the color is for, never what it looks like. --color-text-secondary says “supporting copy”, not “neutral 500”.

Components consume only the semantic layer. That single indirection is what makes the system maintainable: retune a primitive or remap a semantic token and every component updates at once - no component files change. It's also the path to dark mode: the .dark block in theme.css re-points the same tokens at dark values, so components never need dark: prefixes.

Token names mirror the Figma variable paths (text/primary --color-text-primary), so a design spec translates to code without a lookup table. Note the doubled prefix in class names - text-text-primary, bg-background-primary-default - the first segment is the Tailwind utility, the rest is the token's full semantic path.

One token system, two themes

Add .dark to the root element. BoardUI remaps the same semantic tokens, so every component changes with it.

01

Map each theme

Keep light values in :root and dark values in .dark.

02

Use semantic colors

Use tokens like bg-background-primary-default, not raw colors.

03

Keep it centralized

Avoid component-level dark: overrides so changes stay predictable.

Includes persistence and a no-flash initialization script.

View installation guide

One accent, every CTA

Every interactive surface - primary button gradients, checkboxes, radios, switches, sliders, tabs, the selected sidebar item, focus rings - reads from a single --color-accent-50…950 ramp that defaults to blue. Pick any hue below (or a fully custom color) and watch this page re-tint live; charts and status colors deliberately stay put.

Take it home: copy the eleven-variable override and paste it after your theme.css import.

Installation guide

Foreground

Icon fills and inverse/on-color foregrounds - everything drawn on top of a surface that isn't running text.

TokenTailwind classLightDark
--color-foreground-fulltext-foreground-fullwhiteneutral-700
--color-foreground-icon-primarytext-foreground-icon-primaryneutral-950neutral-50
--color-foreground-icon-hovertext-foreground-icon-hoverblackwhite
--color-foreground-icon-secondarytext-foreground-icon-secondaryneutral-500neutral-500
--color-foreground-icon-tertiarytext-foreground-icon-tertiaryneutral-400neutral-600
--color-foreground-icon-quaternarytext-foreground-icon-quaternaryneutral-300neutral-700
--color-foreground-icon-errortext-foreground-icon-errorred-600red-400
--color-foreground-icon-disabledtext-foreground-icon-disabledneutral-300neutral-800
--color-foreground-disabledtext-foreground-disabledneutral-400neutral-700
--color-foreground-disabled-dangertext-foreground-disabled-dangerred-300red-400
--color-input-disabled-foregroundtext-input-disabled-foregroundneutral-300neutral-600
--color-icon-button-disabled-foregroundtext-icon-button-disabled-foregroundneutral-300neutral-500

Text

The type hierarchy: primary for headings and key values, secondary for supporting copy, tertiary for hints, plus disabled and error states.

TokenTailwind classLightDark
--color-text-primarytext-text-primaryneutral-950neutral-50
--color-text-secondarytext-text-secondaryneutral-500neutral-500
--color-text-tertiarytext-text-tertiaryneutral-400neutral-600
--color-text-disabledtext-text-disabledneutral-300neutral-800
--color-text-disabled-dangertext-text-disabled-dangerred-300red-300
--color-text-error-primarytext-text-error-primaryred-500red-400
--color-input-disabled-texttext-input-disabled-textneutral-300neutral-500 / 40%
--color-text-placeholderplaceholder:text-text-placeholderneutral-400neutral-400
--color-text-whitetext-text-whitewhitewhite
--color-text-error-placeholdertext-text-error-placeholderred-400red-400

Background

Surface fills. Full is the outer canvas; primary, secondary, and tertiary describe progressively nested surfaces and their interaction states.

TokenTailwind classLightDark
--color-background-fullbg-background-fullwhiteneutral-925 (#121212)
--color-background-primary-defaultbg-background-primary-defaultwhiteneutral-800
--color-background-inner-defaultbg-background-inner-defaultwhiteneutral-800 / 60%
--color-background-primary-hoverbg-background-primary-hoverneutral-100neutral-700 / 60%
--color-background-primary-activebg-background-primary-activeneutral-200neutral-800
--color-background-primary-disabledbg-background-primary-disabledneutral-100neutral-800
--color-input-disabled-backgroundbg-input-disabled-backgroundneutral-100neutral-800 / 30%
--color-background-secondary-defaultbg-background-secondary-defaultneutral-100neutral-900
--color-background-secondary-hoverbg-background-secondary-hoverneutral-200neutral-800
--color-background-tertiary-defaultbg-background-tertiary-defaultneutral-200neutral-800
--color-background-tertiary-hoverbg-background-tertiary-hoverneutral-300neutral-700
--color-background-tertiary-errorbg-background-tertiary-errorred-100red-950 / 60%
--color-avatar-neutral-backgroundbg-avatar-neutral-backgroundneutral-300background/primary/default
--color-background-quaternary-defaultbg-background-quaternary-defaultneutral-300neutral-300
--color-background-quaternary-hoverbg-background-quaternary-hoverneutral-400neutral-400
--color-background-quaternary-errorbg-background-quaternary-errorred-200red-200
--color-notification-center-backgroundbg-notification-center-backgroundwhiteneutral-900
--color-segmented-control-backgroundbg-segmented-control-backgroundneutral-100neutral-925 (#121212)
--color-theme-toggle-sidebar-backgroundbg-theme-toggle-sidebar-backgroundneutral-200neutral-800
--color-theme-toggle-sidebar-selected-backgroundbg-theme-toggle-sidebar-selected-backgroundwhiteneutral-700

Border

Hairlines and focus rings. Button borders step darker through hover and active; the focus ring is the single blue accent.

TokenTailwind classLightDark
--color-border-button-defaultborder-border-button-defaultneutral-200neutral-700
--color-border-button-hoverborder-border-button-hoverneutral-300neutral-500
--color-border-button-activeborder-border-button-activeneutral-400neutral-600
--color-border-button-whiteborder-border-button-whitewhitezinc-800
--color-border-checkbox-defaultborder-border-checkbox-defaultneutral-300neutral-700
--color-border-checkbox-hoverborder-border-checkbox-hoverneutral-400neutral-500
--color-border-checkbox-activeborder-border-checkbox-activeneutral-400neutral-500
--color-border-component-detail-containerborder-border-component-detail-containerneutral-200neutral-800
--color-border-ai-profile-cardborder-border-ai-profile-cardneutral-200neutral-800
--color-border-tableborder-border-tableneutral-200neutral-800
--color-border-button-groupborder-border-button-groupneutral-200neutral-600 / 60%
--color-border-sidebar-profile-hoverborder-border-sidebar-profile-hoverneutral-300neutral-600
--color-separator-borderborder-separator-borderneutral-200neutral-800
--color-separator-border-strongborder-separator-border-strongneutral-200neutral-700 / 60%
--color-border-focus-ringring-border-focus-ringblue-500blue-500

Graphs

Chart colors. Track is the background bar/ring behind a series, cursor the hover outline and dashed reference line, neutral an “other”-style data slice. The numbered accents are a categorical ramp — each pairs a base fill with a one-tone-darker active used for hover emphasis (the 400 → 500 recipe every chart follows). In charts these are consumed as CSS variables (e.g. fill=“var(--color-chart-1)”) rather than classes.

TokenTailwind classLightDark
--color-chart-trackbg-chart-trackneutral-200neutral-800
--color-chart-cursorbg-chart-cursorneutral-300neutral-700
--color-chart-neutralbg-chart-neutralneutral-300neutral-800
--color-chart-1bg-chart-1teal-400teal-400
--color-chart-1-activebg-chart-1-activeteal-500teal-500
--color-chart-2bg-chart-2lime-400lime-400
--color-chart-2-activebg-chart-2-activelime-500lime-500
--color-chart-3bg-chart-3pink-400pink-400
--color-chart-3-activebg-chart-3-activepink-500pink-500
--color-chart-4bg-chart-4sky-400sky-400
--color-chart-4-activebg-chart-4-activesky-500sky-500
--color-chart-5bg-chart-5purple-400purple-400
--color-chart-5-activebg-chart-5-activepurple-500purple-500
--color-chart-6bg-chart-6blue-400blue-400
--color-chart-6-activebg-chart-6-activeblue-500blue-500
--color-chart-7bg-chart-7emerald-400emerald-400
--color-chart-7-activebg-chart-7-activeemerald-500emerald-500
--color-chart-8bg-chart-8yellow-400yellow-400
--color-chart-8-activebg-chart-8-activeyellow-500yellow-500
--color-chart-agents-barbg-chart-agents-barpurple-300purple-500
--color-chart-agents-bar-activebg-chart-agents-bar-activepurple-400purple-600

State

Semantic feedback colors whose meaning stays stable across themes.

TokenTailwind classLightDark
--color-state-success-texttext-state-success-textlime-800lime-800
--color-state-success-basebg-state-success-baselime-200lime-200
--color-button-ghost-backgroundbg-button-ghost-backgroundblue-100blue-900
--color-button-ghost-hoverbg-button-ghost-hoverblue-200blue-800
--color-button-ghost-activebg-button-ghost-activeblue-300blue-700
--color-button-ghost-foregroundtext-button-ghost-foregroundblue-700blue-300
--color-notification-information-backgroundbg-notification-information-backgroundblue-100blue-800 / 50%
--color-notification-success-backgroundbg-notification-success-backgroundlime-100lime-800 / 50%
--color-notification-error-backgroundbg-notification-error-backgroundrose-100rose-800 / 50%
--color-badge-neutral-backgroundbg-badge-neutral-backgroundneutral-200neutral-800
--color-team-menu-count-backgroundbg-team-menu-count-backgroundneutral-200neutral-700
--color-team-menu-count-foregroundtext-team-menu-count-foregroundneutral-500neutral-400
--color-tab-count-selected-backgroundbg-tab-count-selected-backgroundblue-100blue-800 / 60%
--color-status-lime-backgroundbg-status-lime-backgroundlime-200lime-950 / 60%
--color-status-lime-texttext-status-lime-textlime-800lime-500
--color-status-yellow-backgroundbg-status-yellow-backgroundyellow-200yellow-950 / 60%
--color-status-yellow-texttext-status-yellow-textyellow-800yellow-500
--color-status-rose-backgroundbg-status-rose-backgroundrose-200rose-950 / 60%
--color-status-rose-texttext-status-rose-textrose-800rose-500
--color-status-cyan-backgroundbg-status-cyan-backgroundcyan-200cyan-950 / 60%
--color-status-cyan-texttext-status-cyan-textcyan-800cyan-400
--color-status-blue-backgroundbg-status-blue-backgroundblue-200blue-950 / 60%
--color-status-blue-texttext-status-blue-textblue-800blue-300
--color-status-purple-backgroundbg-status-purple-backgroundpurple-100purple-900 / 50%
--color-status-purple-texttext-status-purple-textpurple-600purple-300
--color-status-dot-green-halobg-status-dot-green-halogreen-100green-800 / 40%
--color-status-dot-yellow-halobg-status-dot-yellow-haloyellow-200yellow-800 / 40%
--color-status-dot-indigo-halobg-status-dot-indigo-haloindigo-100indigo-800 / 40%