Chart legend and key icon

Chart legend names a data series next to its colour, for reading charts. Key icon puts an icon in a circle; use it to draw attention to a metric, feature or list item.

  • Beta
  • Accessibility
  • Figma Chart Legends 57:15695 · Chart Legend Dots 57:15737 · Key Icons 57:15783
  • packages/ui/src/components/ChartLegend, KeyIcon

Beta until design confirms the legend Blue colour (C24) and the key icon colour bindings (C25, FC-12), decides on the colours below 3:1 (C23), and adds a local shadow style for the dots (FC-16).

Preview

Pick a component, then change its props. The preview renders the real component and the code updates with it.

Lessons completed
tsx
import { ChartLegend } from '@nuton/ui'

<ChartLegend color="blue">Lessons completed</ChartLegend>

Installation

Availability

@nuton/ui and @nuton/tokens are private workspace packages. They aren't published to a registry yet (D4: registry deferred; D12: distribution waits on the provenance review). Inside the Nuton monorepo, add them as workspace dependencies. The commands below apply once the packages are published.

1. Add the packages

bash
pnpm add @nuton/ui @nuton/tokens @remixicon/react

Peer dependencies: react and react-dom 18 or later. @remixicon/react supplies the icons you pass to KeyIcon (Remix Icon is Nuton's icon set, D1).

2. Load tokens and component styles once

tsx
// app/layout.tsx (or your app's entry file)
import '@nuton/tokens/tokens.css' // --nu-* design tokens
import '@nuton/ui/styles.css'     // component styles (uses the tokens)

The legend label uses the Label/X Small type tokens, which read --nu-font-body. Map it to Inter as described in the Button font setup. No provider or other setup is needed.

Usage

tsx
import { ChartLegend, KeyIcon } from '@nuton/ui'
import { RiBookOpenLine } from '@remixicon/react'

export function ActivityLegend() {
  return (
    <ul className="legend">
      <li><ChartLegend color="blue">Lessons completed</ChartLegend></li>
      <li><ChartLegend color="orange">Quizzes taken</ChartLegend></li>
    </ul>
  )
}

export function LessonCount() {
  return <p><KeyIcon color="blue" icon={<RiBookOpenLine />} /> 12 lessons</p>
}
  • Defaults: ChartLegend and ChartLegendDot are gray (the dot is md); KeyIcon is stroke, gray, 40.
  • Give every series a ChartLegend with the series name. Use ChartLegendDot on its own only where text sits next to it, such as a tooltip row.
  • Put two or more legends in a list (<ul> of <li>), so screen readers announce how many series there are.
  • Pass a Remix icon through icon. Leave label off when text next to the key icon says the same thing.

Variants and sizes

The family has three parts. ChartLegendDot is the coloured mark; ChartLegend is a small dot plus the series name; KeyIcon is an icon in a circle with its own palette and five sizes.

Chart legend colours

  • Gray
  • Light gray
  • Blue
  • Orange
  • Red
  • Green
  • Yellow
  • Purple
  • Sky
  • Pink
  • Teal
  • Disabled

Figma discrepancy: legend Blue (C24, FC-13)

In Figma, the Chart Legends “Blue” instance overrides its dot to State/Success/Base (green), and “Disabled” is a Teal dot with overrides. Code builds the legend from the dot component, so legend Blue is Primary blue. Awaiting design confirmation.

Legend dots: colour × size

All 11 colours at both sizes. The dot is 12px in both; size sets the frame around it.

md
sm
md · 20px frame
sm · 16px frame
PartFrameInsetMarkDetails
ChartLegendDot size="md"20 × 20412px circle2px inside Stroke/White, shadow regular-shadow/small (interim token, FC-16)
ChartLegendDot size="sm"16 × 162
ChartLegend16 tall—Small dot4px gap, Label/X Small (12px, 500) with a 16px line box, Text/Sub-600

Measured in the browser (legend 16 tall). Figma binds the legend text to a remote Label/X Small style (Satoshi); code uses the local Nuton Label/X Small (C22).

Key icon appearance

Stroke: Bg/White, 1px inside Stroke/Soft-200, regular-shadow/x-small. Lighter: State/<colour>/Lighter fill, no border. The icon is State/<colour>/Base (gray: Icon/Sub-600).

Key icon sizes

64
56
48
40
32
SizeFigma nameCircleInsetIcon
642X-Large64 × 641632
56X-Large56 × 561428
48Large48 × 481224
40Medium (default)40 × 401020
32Small32 × 32620

Verified in the browser against Figma geometry.

Key icons: appearance × colour × size

Every Figma variant: 2 appearances × 9 colours × 5 sizes.

Stroke

64
56
48
40
32

Lighter

64
56
48
40
32

Figma discrepancy: key icon colours (C25, FC-12)

Code follows the Figma bindings, including three oddities: Blue Lighter uses State/Purple/Lighter for its fill; Purple Lighter binds a remote feature/lighter token (code uses local State/Purple/Lighter, C22); and “Teal” uses State/Verified (sky) values, not State/Teal. Design to confirm whether Blue should use Primary/Lighter and Teal should use State/Teal.

Colour tokens

ColourDot (--nu-chart-color)Key icon (--nu-key-icon-fg / --nu-key-icon-tint)
GrayState/Faded/BaseIcon/Sub-600 / State/Faded/Lighter
Light grayIcon/Disabled-300Not available
BlueState/Primary/BaseState/Primary/Base / State/Purple/Lighter (C25)
OrangeState/Warning/BaseState/Warning/Base / Lighter
RedState/Error/BaseState/Error/Base / Lighter
GreenState/Success/BaseState/Success/Base / Lighter
YellowState/Pending/BaseState/Pending/Base / Lighter
PurpleState/Purple/BaseState/Purple/Base / Lighter
SkyState/Verified/BaseNot available
PinkState/Feature/BaseState/Feature/Base / Lighter
TealState/Teal/BaseState/Verified/Base / Lighter (C25)

States

None of these components is interactive, so there are no hover, focus or pressed states. The legend has a disabled state; the key icon is either decorative or labelled.

Lessons completed
Legend: defaultSeries colour dot and Text/Sub-600 label.
Lessons completed
Legend: disabledA series that is hidden or not available. Dot Icon/Disabled-300, text Text/Disabled-500 (4.23:1, C8).
Dot: default and disableddisabled on the dot alone swaps its colour to Icon/Disabled-300.
12 lessons
Key icon: decorativeNo label. Hidden from assistive tech; the text beside it carries the meaning.
Key icon: labelledWith label, it's an img named “Reading lesson”. Use it when the icon alone carries meaning.
Not interactive
Hover, focus, pressedNone. To let people show and hide series, wrap each legend in a button (see Series toggle).

State tokens

These custom properties are set by the component from its props, on the element itself. Use the props; the properties are listed for reference.

TokenElementDefaultDisabled
--nu-chart-color.nu-chart-dotThe colour's base token (see Colour tokens)Icon/Disabled-300
Legend text colour.nu-chart-legendText/Sub-600Text/Disabled-500
--nu-key-icon-size, --nu-key-icon-glyph.nu-key-icon40 / 20 (by size)—
--nu-key-icon-fg, --nu-key-icon-tint.nu-key-iconBy color (see Colour tokens)—

Composition examples

Series toggle

Click a legend to hide or show its series. Each legend sits inside a real Button with aria-pressed; a hidden series shows the disabled legend. The chart has a text summary for screen readers.

Biology 101 · activity this week

The disabled legend text is 1.52:1 (C23). The button's pressed state, not the grey text, tells assistive tech the series is hidden.

Chart legend

Weekly activity
  • Lessons completed
  • Quizzes taken
  • Hidden: revision time

Key icons in a space summary

Next to text, the key icon is decorative: leave label off.

  • 12 lessons
  • 34 students
  • 6 h of content

Labelled key icons

When the icon is the only cue, such as a lesson type in a list, pass label so it's announced.

  • Photosynthesis
  • Cell structure
  • Plant cells check-in

Use only colours at 3:1 or higher for meaningful key icons: not green, yellow or teal lighter (C23).

API reference

ChartLegend props

ChartLegend props
PropTypeDefaultDescription
childrenrequiredReactNode—The series name.
colorChartColor'gray'The dot colour: 'gray' | 'light-gray' | 'blue' | 'orange' | 'red' | 'green' | 'yellow' | 'purple' | 'sky' | 'pink' | 'teal'. Always renders a small dot.
disabledbooleanfalseA series that is hidden or not available (Figma Disabled). Greys the dot and the text. Purely visual.
refRef<HTMLSpanElement>—Forwarded to the outer span.
…restOmit<HTMLAttributes<HTMLSpanElement>, 'color'>—Any other span attribute (className, id, aria-*…), applied to the outer span.

ChartLegendDot props

ChartLegendDot props
PropTypeDefaultDescription
colorChartColor'gray'One of the 11 chart colours.
size'sm' | 'md''md'Frame 16 / 20px. The dot is 12px in both.
disabledbooleanfalseSwaps the colour to Icon/Disabled-300.
refRef<HTMLSpanElement>—Forwarded to the span.
…restOmit<HTMLAttributes<HTMLSpanElement>, 'color'>—Any other span attribute. The dot always renders aria-hidden="true".

KeyIcon props

KeyIcon props
PropTypeDefaultDescription
iconrequiredReactNode—A Remix icon (D1), for example <RiUser6Line />.
appearance'stroke' | 'lighter''stroke'Stroke: white with a 1px border and shadow. Lighter: tinted fill (Figma Style).
colorKeyIconColor'gray''gray' | 'blue' | 'orange' | 'red' | 'green' | 'yellow' | 'purple' | 'pink' | 'teal'.
sizeKeyIconSize4032 | 40 | 48 | 56 | 64, the circle in pixels.
labelstring—Accessible name. With it the key icon is role="img"; without it, aria-hidden.
refRef<HTMLSpanElement>—Forwarded to the span.
…restOmit<HTMLAttributes<HTMLSpanElement>, 'color'>—Any other span attribute.

Styling hooks

ChartLegendDot renders .nu-chart-dot with data-color, data-size and data-disabled. ChartLegend renders .nu-chart-legend (with data-disabled) around a small dot and .nu-chart-legend__label. KeyIcon renders .nu-key-icon with data-appearance, data-color and data-size. Use props rather than styling these attributes.

Accessibility

Keyboard

KeyBehaviour
TabSkips legends, dots and key icons: they aren’t focusable. In a series toggle, focus moves to each wrapping button.
Enter / SpaceNothing on the components themselves. On a wrapping button, toggles the series.

Screen readers

The legend reads as its text; the dot is always hidden. Several legends in a list announce the count. A key icon is hidden unless label is set; then it's an img with that name. The disabled state isn't announced, so say it in text or with aria-pressed.

Focus

None of the components takes focus. When you wrap a legend in a Button, the button's focus ring applies.

Contrast and colour

Dots as chart marks on white: Light Gray 1.53, Yellow 2.10 and Green 2.85 are below 3:1; Sky 3.27, Orange 3.44 and the rest pass. Key icons: Gray, Blue, Purple, Red, Pink, Orange and Teal Stroke (3.27) are 3:1 or higher; Green (2.85 / 2.59), Yellow (2.10 / 2.02) and Teal Lighter (2.78) are below, so use them only decoratively. Disabled legend text is 1.52 (C23, as C8). The legend text names the series, so colour is never the only cue.

Touch and pointer

Not targets. A series toggle's size="sm" button is 36px tall, above the 24 × 24 minimum (WCAG 2.5.8).

You must: give every series a text legend; put several legends in a list; pair low-contrast series with patterns or direct labels in the chart itself; pass label only when the key icon alone carries meaning.

Figma mapping

FigmaVariantsCode
Chart Legend Dots [1.1] (57:15737)11 colours × Medium (20) · Small (16)ChartLegendDot color size="md" | "sm"
Chart Legends [1.1] (57:15695)11 colours + DisabledChartLegend color disabled
Key Icons [1.1] (57:15783)Stroke · Lighter × 9 colours × 2X-Large (64) · X-Large (56) · Large (48) · Medium (40) · Small (32)KeyIcon appearance color size icon label

Figma's description says “9 distinct colour options”; the dot and legend components have 11 (FC-13). Payment Icons (57:15965) sit on the same Figma page. They aren't part of this family and are already on the D9 clean-up list.

Guidelines and related components

Use these for

  • ChartLegend: naming each series of a chart, such as lessons completed and quizzes taken.
  • ChartLegendDot: a colour key next to existing text, such as a tooltip row.
  • KeyIcon: highlighting a metric, feature or list item, such as a space's lesson count.

Don't use them for

  • Status (online, completed). Show status as text; colour alone isn't enough.
  • Actions. A key icon isn't a button; use an icon-only Button with an aria-label.
  • A person or space image. Use Avatar.

Do and don't

  • Lessons completed
  • Quizzes taken
DoName every series in text. The label carries the meaning, so the chart works without colour.
Don'tDon't use bare dots as a legend. Colour alone can't tell people which series is which.
DoUse high-contrast colours for meaningful key icons. Blue, purple, red and gray stay visible at 3:1 or higher.
Don'tDon't give a meaning to a low-contrast key icon. Yellow is 2.02:1 in the lighter style and hard to see (C23).
12 lessons
DoLeave label off when text says the same thing. Screen readers hear “12 lessons” once.
12 lessons
Don'tDon't label a key icon that repeats its text. “Lessons, 12 lessons” is noise.

Common mistakes

  • Putting an onClick on a legend. It isn't focusable or announced as a control; wrap it in a Button.
  • Relying on the greyed disabled legend to say a series is hidden. Pair it with aria-pressed or text.
  • Matching chart colours to dots by eye. Use the same State tokens the dot uses (see Colour tokens).
  • Setting the dot size on a legend. ChartLegend always uses the small dot.