# MusicStaff (/docs/charts/music-staff)

MusicStaff answers "what's the shape of this short series?" by reading it as a melody: each value is a note, its
**pitch** (vertical position on a five-line staff) is the value, and left-to-right is time. Pitch is the only channel —
there are no clefs, stems, beams, or bar lines, because every other notation convention would be decoration. The read is
in steps (nine to thirteen positions), so exact values steer to `Sparkline` with a label.

```tsx
import { MusicStaff } from "@microcharts/react/music-staff";

<MusicStaff data={[3, 5, 4, 8, 6, 9, 7, 11]} label="last" title="Sprint melody" />
```

## Install

```tsx
import { MusicStaff } from "@microcharts/react/music-staff";

<MusicStaff data={weeks} title="Sprint melody" />
```

Setup (package + stylesheet): [Quickstart](/docs/quickstart#set-up-with-an-ai-agent) or paste [`/agent-setup.md`](/agent-setup.md) into your agent.


## When to use it

- **Good for** — a weekly-rhythm read in a sentence, the shape of a sprint or short series in a cell, or a per-channel
  melody in a tab.
- **Avoid for** — exact values (Sparkline with a label), long series (over sixteen points), or trends where the exact
  slope matters.


## Variants

```tsx
<MusicStaff data={[3, 5, 4, 8, 6, 9]} mode="staff" />
<MusicStaff data={[3, 5, null, 8, 6]} />
```

## Edge cases

```tsx
<MusicStaff data={[7]} />
```

```tsx
// every value null — no notes, no contour line, just the staff
<MusicStaff data={[null, null, null]} />
```

```tsx
<MusicStaff data={[3000, 5200, 4100, 8300, 6400]} label="last" locale="de-DE" />
```

A single value draws one note and no contour line — a melody needs at least two notes to have a shape. An all-`null`
series draws the bare staff with no notes at all; the accessible name falls back to `describeSeries`'s own no-data
phrasing. With a `locale`, the trailing `label="last"` value follows that locale's own grouping and decimal marks.


## Why this default

The ledger mode is the default because clipping pitch silently is worse than two extra hairline ledger ticks — a note
above or below the staff still reads truly. `mode="staff"` exists for dense cells where ledger lines would collide with
a neighbour; there, out-of-range pitches clamp to the nearest staff line or space instead, trading visual precision for
a collision-free cell — the accessible summary is unaffected either way, since it describes the raw values, not the
clamped pixel positions. Two adjacent equal values are spaced by the time axis, never dodged vertically, because moving
a note vertically would change its pitch — and pitch is the data.

## Accessibility

MusicStaff reuses the same natural-language summary as `Sparkline`, verbatim — for `[3, 5, 4, 8, 6, 9]`, **"Trending up
200%. Range 3 to 9. Last value 9."** The interactive entry steps the notes with ←/→, announcing each as **"Point 3 of 6:
4."**

The interactive entry follows the shared [interaction contract](/docs/accessibility#one-interaction-contract):
arrow keys rove between units on both axes, `Home` and `End` jump to the ends, and a click, tap, `Enter` or
`Space` selects a unit — pinning its readout so it survives blur, until you select it again or press `Escape`.
On touch, a tap pins and a drag scrubs.

## Props

| Prop | Type | Description |
| --- | --- | --- |
| `data` (required) | `(number \| null)[]` | The series; null = a rest. |
| `mode` | `"staff" \| "ledger"` | ledger (±2, default) or staff (clamp on-staff). |
| `label` | `"none" \| "last"` | Print the final value after the last note. |
| `animate` | `boolean` | (interactive) Opt-in entrance motion when the chart mounts client-side — add `import "@microcharts/react/motion"` once. Inert on the server, on hydrated server HTML, and under `prefers-reduced-motion`. |

Plus the shared grammar — `data`, `domain`, `color`, `title`, `summary`, `format` — and the layout props (`width`, `height`, `className`, `style`) that every chart accepts. Interactive entries also share `animate` and `live`, and — wherever a chart has more than one navigable unit — `onActive`, `onSelect`, `selectedIndex` and `defaultSelectedIndex`; and — wherever the chart shows a hover value — `readout`. See [the shared grammar](/docs/quickstart#the-shared-grammar).
