Legend
The key to a chart, map, graph or timeline: colors, shapes and line styles with labels, grouping and optional toggles.
npx prodular-ui add legendSeries and encodings
Toggle series on a chart, and a grouped key for severity shapes and link styles.
SeverityCriticalHighElevatedRoutine
LinksConfirmedSuspectedHistorical
import * as React from "react"
import { Legend, LegendGroup, LegendItem } from "@/components/ui/legend"
const series = [ { id: "card", label: "Card", color: "chart-1", values: [32, 41, 38, 52, 49, 61, 58] }, { id: "ach", label: "ACH", color: "chart-2", values: [18, 22, 25, 24, 30, 29, 34] }, { id: "wire", label: "Wire", color: "chart-3", values: [8, 6, 9, 12, 10, 14, 13] },]
export default function LegendChart() { const [hidden, setHidden] = React.useState<string[]>([]) const max = 65 return ( <div className="flex w-full max-w-lg flex-col gap-4"> <Legend aria-label="Payment methods"> {series.map((s) => ( <LegendItem key={s.id} color={s.color} shape="line" label={s.label} value={`$${s.values.at(-1)}k`} active={!hidden.includes(s.id)} onActiveChange={(on) => setHidden((h) => (on ? h.filter((x) => x !== s.id) : [...h, s.id]))} /> ))} </Legend> <svg viewBox="0 0 300 120" className="h-40 w-full" role="img" aria-label="Collections by payment method over seven days"> {series .filter((s) => !hidden.includes(s.id)) .map((s) => ( <polyline key={s.id} fill="none" stroke={`var(--${s.color})`} strokeWidth="2" strokeLinejoin="round" points={s.values.map((v, i) => `${(i / 6) * 300},${120 - (v / max) * 110}`).join(" ")} /> ))} </svg> <Legend orientation="vertical"> <LegendGroup label="Severity"> <LegendItem color="severity-critical" shape="diamond" label="Critical" /> <LegendItem color="severity-high" shape="triangle" label="High" /> <LegendItem color="severity-elevated" shape="square" label="Elevated" /> <LegendItem color="severity-routine" shape="circle" label="Routine" /> </LegendGroup> <LegendGroup label="Links"> <LegendItem color="muted-foreground" shape="line" label="Confirmed" /> <LegendItem color="muted-foreground" shape="dashed" label="Suspected" /> <LegendItem color="muted-foreground" shape="dotted" label="Historical" /> </LegendGroup> </Legend> </div> )}Anatomy
<Legend aria-label="Payment methods"> <LegendItem color="chart-1" shape="line" label="Card" active={on} onActiveChange={setOn} /></Legend>Guidance
Use it when
- Any visual where color, shape or line style carries meaning.
- onActiveChange to let people hide a series.
- LegendGroup when one visual has more than one encoding.
Avoid
- Color as the only difference between items. Give each a shape or line style too.
- Legends for a single series. Label it in the title.
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.
- Use the same color token and shape as the visual draws, for example color="severity-high" with shape="triangle".
- Give Legend an aria-label when there is more than one on screen.
- Toggles need onActiveChange and active; they render as buttons with aria-pressed.
API
Legend
| Prop | Type | Default | Description |
|---|---|---|---|
| orientation | "horizontal" | "vertical" | "horizontal" | Wraps in a row, or stacks. |
LegendItem
| Prop | Type | Default | Description |
|---|---|---|---|
| color | string | A token name ("chart-1", "severity-high") or a CSS color. | |
| shape | "circle" | "square" | "diamond" | "triangle" | "line" | "dashed" | "dotted" | "circle" | The mark. |
| active | boolean | true | Inactive items dim and strike through. |
| onActiveChange | (active: boolean) => void | Makes the item a toggle. |
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 legend# or, with the registry in components.jsonnpx shadcn@latest add @prodular/legend