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

MusicStaff reads a short series as a melody, so its shape lands in one look: each value is a note on a five-line staff,
**pitch** (vertical position) is the value, and left-to-right is time. Pitch is the only channel, so there are no clefs,
stems, beams, or bar lines. The read is in steps (nine to thirteen positions), so exact values steer to `Sparkline` with
a label. Two adjacent equal values are spaced along the time axis and never dodged vertically, because moving a note
vertically would change its pitch.

```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.

## Try it

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

<MusicStaff
  data={weeks}
/>
```

## When to use it

Use it 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. For exact values use Sparkline with a label; skip it for long series (over sixteen points) and for trends
where the exact slope matters.

## Sizing

**staff mode clamps the pitch on-staff**

```tsx
<MusicStaff data={weeks} mode="staff" />
```

**a rest (null) leaves a gap**

```tsx
<MusicStaff data={[3, 5, null, 8, 6]} />
```

## Variants

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

Ledger mode is the default: a note above or below the staff sits on a hairline ledger tick and keeps its true pitch,
rather than being clipped. `mode="staff"` is for dense cells where ledger lines would collide with a neighbour; there,
out-of-range pitches clamp to the nearest staff line or space, trading visual precision for a collision-free cell. The
accessible summary is the same either way, since it describes the raw values, not the clamped pixel positions.

## 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, since a melody needs at least two notes to have a shape. An
all-`null` series draws the bare staff with no notes at all, and 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.

## Four homes

**In a sentence**

```tsx
<p>
  Sprint velocity{" "}
  <span className="mc-inline">
    <MusicStaff data={weeks} width={90} height={20} summary={false} />
  </span>{" "}
  — peaked week 4.
</p>
```

**In a table cell**

```tsx
<td><MusicStaff data={team.weeks} width={72} height={18} /></td>
```

**In a KPI card**

```tsx
<div className="kpi"><span className="figure">11</span><MusicStaff data={weeks} width={200} height={28} /></div>
```

**In a tab header**

```tsx
<button className="tab">Platform <MusicStaff data={weeks} width={72} height={20} /></button>
```

## Accessibility

MusicStaff reuses `Sparkline`'s natural-language summary verbatim. For `[3, 5, 4, 8, 6, 9]` that is **"Trending up 200%.
Range 3 to 9. Last value 9."** The interactive entry steps the notes with ←/→ and announces 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, press `Escape`, or
press outside the chart. 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. |
| `fontSize` | `number` | Type size of the last-note label, in viewBox units. Defaults from `height`. |
| `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).
