Token color
Resolves color tokens to sRGB for canvas, WebGL, MapLibre, D3 and chart libraries, and updates them when the theme or mode changes.
npx prodular-ui add token-colorCanvas
Bars drawn on a canvas with chart and border tokens. Switch the theme or mode and they redraw.
Resolving colors…
import * as React from "react"
import { useTokenColors } from "@/lib/token-color"
const values = [12, 19, 15, 24, 21, 30, 27, 34]const tokens = ["chart-1", "chart-2", "border", "muted-foreground"] as const
export default function TokenColorCanvas() { const ref = React.useRef<HTMLCanvasElement>(null) // Resolved to hex, and resolved again when the theme or mode changes. const colors = useTokenColors(tokens)
React.useEffect(() => { const canvas = ref.current if (!canvas || !colors) return const dpr = window.devicePixelRatio || 1 const w = canvas.clientWidth const h = canvas.clientHeight canvas.width = w * dpr canvas.height = h * dpr const ctx = canvas.getContext("2d")! ctx.scale(dpr, dpr) ctx.clearRect(0, 0, w, h) ctx.strokeStyle = colors.border ctx.beginPath() ctx.moveTo(0, h - 0.5) ctx.lineTo(w, h - 0.5) ctx.stroke() const bw = w / values.length values.forEach((v, i) => { ctx.fillStyle = i === values.length - 1 ? colors["chart-1"] : colors["chart-2"] const bh = (v / 36) * (h - 16) ctx.fillRect(i * bw + 6, h - bh, bw - 12, bh) }) ctx.fillStyle = colors["muted-foreground"] ctx.font = "11px ui-sans-serif, system-ui" ctx.fillText("Drawn on a canvas with theme colors", 4, 12) }, [colors])
return ( <div className="flex w-full max-w-md flex-col gap-2"> <canvas ref={ref} className="h-40 w-full" role="img" aria-label="Weekly volume, eight weeks, rising" /> <p className="text-(length:--text-ui) text-muted-foreground"> {colors ? `chart-1 is ${colors["chart-1"]} in this theme.` : "Resolving colors…"} </p> </div> )}Anatomy
const colors = useTokenColors(["chart-1", "border"])useEffect(() => { if (colors) map.setPaintProperty("sites", "circle-color", colors["chart-1"])}, [colors])Guidance
Use it when
- Renderers that take color strings or numbers instead of CSS: canvas 2D, WebGL, MapLibre styles, D3 scales.
- useTokenColors in React, so colors update with the theme.
- tokenColor(token, { format: "array" }) for WebGL and image data.
Avoid
- Hard-coding hex values that only match one theme.
- Painting a pixel and reading it back to convert colors.
- Calling tokenColor during server rendering; it returns null there.
Rules for AI agents
Published in llms-full.txt, the registry and the MCP server, so coding agents follow them when they build with this component.
- Resolve colors in an effect or with useTokenColors, and redraw when they change.
- Pass token names without var(): "chart-1", "severity-high", "--border".
- Pass element to read a token under a scoped data-theme or .dark.
API
tokenColor
| Prop | Type | Default | Description |
|---|---|---|---|
| (token, options) | string | [r, g, b, a] | null | options: format ("hex" | "rgb" | "rgba" | "array"), element, alpha. |
useTokenColors
| Prop | Type | Default | Description |
|---|---|---|---|
| (tokens, options) | Record<token, string> | null | Resolved colors, null until mounted. |
onTokensChange
| Prop | Type | Default | Description |
|---|---|---|---|
| (callback, element?) | () => void | Subscribes to theme, mode and OS color scheme changes. Returns the unsubscribe. |
Installation
The Prodular UI CLI adds the source to components/ui with everything it depends on. In a project that already uses shadcn/ui, the shadcn CLI installs it from the Prodular registry too. See Installation for the first setup.
npx prodular-ui add token-color# or, with the registry in components.jsonnpx shadcn@latest add @prodular/token-color