Components

Status legend

A wrap-friendly grid of colored-dot + label + value columns used above status-distribution charts (Succeeded / Declined / Refunded / Error / Pending / Created) and dual-axis charts (Payments primary + Conversion rate secondary). Each item stacks [dot + label muted] then [value foreground medium]. Purely display — no interactivity. Use ProviderLegendRow when you need click-to-filter behavior.

Updated Aug 6, 2026 by Leonardo Posada

Anatomy

A flex-wrap container that lays out N columns with gap-x-8 gap-y-3. Each column has two rows: first row = dot + text-xs muted label; second row = text-base font-medium foreground value. Wraps automatically at container width.

Succeeded
13,880,000
Declined
7,751,000
Refunded
258,628
Error
20,338
Pending
337
Created
93
  1. 1
    Container

    flex flex-wrap items-start gap-x-8 gap-y-3. Wraps to as many rows as the container width allows.

  2. 2
    Dot

    size-2 rounded-full swatch. Color from item.color — prefer var(--chart-N) / var(--primary).

  3. 3
    Label

    text-xs text-muted-foreground. Series name (e.g. 'Succeeded').

  4. 4
    Value

    text-base font-medium text-foreground. Pass a formatted string (tabular-nums recommended for cross-column comparability).

Recipes

Six-series (Volume status distribution)

The canonical Insights shape: 6 payment statuses (Succeeded / Declined / Refunded / Error / Pending / Created) rendered with their current volume. Wraps naturally on narrow cards.

Succeeded
13,880,000
Declined
7,751,000
Refunded
258,628
Error
20,338
Pending
337
Created
93
<StatusLegend items={[
  { key: "succeeded", label: "Succeeded", color: "var(--chart-6)",  value: "13,880,000" },
  { key: "declined",  label: "Declined",  color: "var(--chart-5)",  value: "7,751,000"  },
  { key: "refunded",  label: "Refunded",  color: "var(--chart-3)",  value: "258,628"    },
  { key: "error",     label: "Error",     color: "var(--chart-4)",  value: "20,338"     },
  { key: "pending",   label: "Pending",   color: "var(--chart-17)", value: "337"        },
  { key: "created",   label: "Created",   color: "var(--chart-7)",  value: "93"         },
]} />
Dual (Payments + Conversion rate)

The composed dual-axis card legend: two columns naming the two series (primary bar + secondary line) with their current values above the chart body.

Payments
2,283,428
Conversion rate
60.12%
<StatusLegend items={[
  { key: "payments",   label: "Payments",        color: "var(--primary)", value: "2,283,428" },
  { key: "conversion", label: "Conversion rate", color: "var(--chart-1)", value: "60.12%"    },
]} />

Import

Copy this import line at the top of the file where you compose this atom.

StatusLegend is a pure display atom — no state, no callbacks. Compose it as the first child of a ChartCard body, above the chart itself.
import { StatusLegend, type StatusLegendItem } from "@/components/ui/status-legend";

Props

Everything else from the underlying HTML or Radix primitive is forwarded via ...props.

StatusLegend

PropTypeDefaultDescription
itemsStatusLegendItem[] (required)The columns to render. See below.
classNamestringExtra classes on the outer flex-wrap container.

StatusLegendItem

PropTypeDefaultDescription
keystring (required)Stable key used for React reconciliation.
labelstring (required)Series label. text-xs, muted.
colorstring (required)Dot color. Prefer var(--chart-N) / semantic tokens.
valueReactNode (required)Value under the label. Pass a formatted string (with tabular-nums when comparing across columns).

Related

Cross-links to atoms and patterns you may reach for next.

  • Provider legend rowInteractive sibling. Use when you need click-to-filter behavior with horizontal scroll.
  • Chart cardCanonical host — StatusLegend goes inside ChartCard's body above the chart.
  • ChartThe chart primitive that renders the series. StatusLegend names the same colors ChartConfig assigns to each dataKey.