Data display / Charts
Charts
<ChartContainer />StableToken-driven recharts primitives plus the dashboard blocks built on them: MetricCard (label · info tooltip · tabular value · delta · sparkline) and ChartTabs (metric tabs over a swappable line/bar/area panel). Data colors come from a dedicated categorical palette (--chart-1 … --chart-12) plus sequential and diverging scales — never the semantic status colors. Tooltips, legends, axes, and grids are pre-styled to match the system and adapt to dark mode automatically.
Data color palette
The three data scales. Categorical for unordered series, sequential for ordered intensity, diverging for signed values around a midpoint.
Categorical · 12 series
Unordered, equal-weight series. Pull colors in order — var(--chart-1) … var(--chart-12). Oklch-tuned so adjacent series stay distinct. Never use the semantic status colors for data.
Sequential · single-hue ramp
Ordered / continuous data (intensity, density, heatmaps). var(--chart-sequential-1…6), low → high. Any tone ramp can serve as a sequential scale.
Diverging · around a midpoint
Signed data that diverges from a neutral zero (gains vs losses, above/below target). var(--chart-diverging-1…7) — crimson ← neutral → cobalt.
Variants
Each type composes recharts directly (shadcn's model) inside ChartContainer. Series colors are assigned via the config's color field and referenced as var(--color-{key}); per-datum charts (donut, scatter, sankey) use seriesColor(i) from @/lib/chart.
const config = {commits: { label: "Commits", color: "var(--chart-1)" },offers: { label: "Offers", color: "var(--chart-2)" },visits: { label: "Visits", color: "var(--chart-3)" },} satisfies ChartConfig<ChartContainer config={config} className="h-[260px] w-[440px]"><BarChart accessibilityLayer data={data}><CartesianGrid vertical={false} /><XAxis dataKey="week" tickLine={false} axisLine={false} /><YAxis tickFormatter={formatCompact} /><ChartTooltip content={<ChartTooltipContent />} /><ChartLegend content={<ChartLegendContent />} /><Bar dataKey="commits" fill="var(--color-commits)" radius={4} /><Bar dataKey="offers" fill="var(--color-offers)" radius={4} /><Bar dataKey="visits" fill="var(--color-visits)" radius={4} /></BarChart></ChartContainer>
Composition
The dashboard blocks: MetricCard (every state — info tooltip, direction-derived delta tones with overrides, metadata, sparkline slot), ChartTabs (metric tabs over swappable area/bar panels, full keyboard + aria via Radix Tabs, selected = tint + accent at regular weight), and charts inside plain Card surfaces.
The Transfers card is the interactive variant — hover it, or click through (info stays independently clickable).
{/* interactive variant (opt-in): href or onClick makes the whole cardthe target — hover = soft accent fill only, press scale, focus ring;the info tooltip stays independently clickable above the overlay */}<MetricCardlabel="Transfers"info="Athletes who entered the portal and moved programs this season."value="1,118"delta={{ value: "+1215%", direction: "up" }}metadata="vs last season"trailing={<ChartSparkline data={trend} color="var(--chart-1)" className="w-20" />}href="/reports/transfers"/>{/* down can be good — override the direction-derived tone */}<MetricCard label="Avg. days in portal" value="41"delta={{ value: "-12%", direction: "down", tone: "success" }}metadata="down is good — faster placements" />
Source
The wrapper is a thin re-export; the actual styling lives in the shadcn primitive.