Lab

PianoRoll

The headless PianoRoll of @audio-ui/react: its parts, what each renders and owns, and their props.

pnpm add @audio-ui/react
import { PianoRoll } from "@audio-ui/react/piano-roll";
ExportKindWhat it is
PianoRoll.KeyfunctionOne key, placed along the keyboard for its pitch.
PianoRoll.KeyLabelfunctionThe name of the key it sits in, such as "C4".
PianoRoll.GridfunctionThe surface notes are drawn on: a timeline lane, with the roll's rows stacked down it.
PianoRoll.KeysfunctionThe keyboard down the side of the roll: a Piano laid out on the roll's rows, low end at the bottom.
PianoRoll.MarqueefunctionThe selection rectangle being dragged across the grid; renders nothing the rest of the time.
PianoRoll.NotefunctionOne note, placed at its start and pitch: on the timeline's units across and on its row down.
PianoRoll.NoteHandlefunctionOne edge of the note it sits in, dragged to change the note's length: the end makes it longer or shorter, the start trims it from the front while its end stays put.
PianoRoll.NotesfunctionRenders children once per note, in the order they are read: by start, then from the highest pitch down.
PianoRoll.RootfunctionGroups the parts of a piano roll and owns its notes, its selection and the pitches it draws.
PianoRoll.RowfunctionThe band a pitch takes across the grid, for shading black-key rows, the rows of the roll's scale and of its root, or ruling where an octave starts.
PianoRoll.RowsfunctionRenders children once per row, highest pitch first: the place to put a PianoRoll.Row on the grid, or a PianoRoll.Key in the keys.
PianoRoll.SelectionSpanfunctionThe time the selected notes cover, from the earliest start to the latest end, as a band from top to bottom of what it sits in: the grid, the velocity lane or the ruler.
PianoRoll.StretchHandlefunctionOne edge of the selection's span, for its SelectionSpan: a drag stretches the selected notes in time from the other edge, on the grid unless Cmd/Ctrl is held.
PianoRoll.VelocityfunctionOne note's velocity, or its chance in a level="chance" lane, as a bar from the bottom of the lane: its height is the value, through the --piano-roll-level CSS variable.
PianoRoll.VelocityLanefunctionA strip under the grid where each note's velocity, or with level="chance" its chance to play, stands as a bar placed at the note's start: a timeline lane, like the grid.

Anatomy

Import the registry components for the ready-made look, or compose the primitive's parts yourself.

import { PianoRoll, Timeline } from "@audio-ui/react";

<Timeline.Root duration={16} snapStep={1}>
  <PianoRoll.Root>
    <PianoRoll.Keys>
      <PianoRoll.Rows>
        {(pitch) => (
          <PianoRoll.Key pitch={pitch}>
            <PianoRoll.KeyLabel />
          </PianoRoll.Key>
        )}
      </PianoRoll.Rows>
    </PianoRoll.Keys>
    <PianoRoll.Grid aria-label="Notes">
      <PianoRoll.Rows>{(pitch) => <PianoRoll.Row pitch={pitch} />}</PianoRoll.Rows>
      <PianoRoll.SelectionSpan>
        <PianoRoll.StretchHandle edge="start" />
        <PianoRoll.StretchHandle edge="end" />
      </PianoRoll.SelectionSpan>
      <PianoRoll.Notes>
        {(note) => (
          <PianoRoll.Note key={note.id} note={note}>
            <PianoRoll.NoteHandle edge="start" />
            <PianoRoll.NoteHandle edge="end" />
          </PianoRoll.Note>
        )}
      </PianoRoll.Notes>
      <PianoRoll.Marquee />
    </PianoRoll.Grid>
    <PianoRoll.VelocityLane aria-label="Velocity">
      <PianoRoll.Notes>
        {(note) => <PianoRoll.Velocity key={note.id} note={note} />}
      </PianoRoll.Notes>
    </PianoRoll.VelocityLane>
  </PianoRoll.Root>
</Timeline.Root>;

API reference

Root

Groups the parts of a piano roll and owns its notes and selection. Must be used within a Timeline. Renders a <div> element.

Props · 20

Data attributes · 5

data-disabled
Present when disabled.
data-editing
Present while a gesture edits the notes.
data-folded
Present when folded.
data-has-selection
Present while notes are selected.
data-mode
"draw" or "select".

Keys

The keyboard down the side: a Piano laid out on the roll's rows, low end at the bottom. Pressing a key sounds it through the roll's onNoteOn; with Shift, pressing it (or Shift + Enter) selects every note on its row, or deselects them when they all are. Put a PianoRoll.Key per row inside, with PianoRoll.Rows. Renders a <div> element.

Rows

Renders children once per row, from the highest pitch down: the place to put a PianoRoll.Key or a PianoRoll.Row. Renders no element of its own.

Props · 1

Key and KeyLabel

The same parts as Piano: a key of the keyboard, and its label.

Grid

The surface notes are drawn on: a timeline lane, with the roll's rows stacked down it. A press on empty grid draws a note (mode="draw"), whose end then follows the pointer, or starts a selection rectangle, Shift adding to what is selected; in that mode a double-click draws. Focused, Enter adds a note at the playback position, Escape clears the selection and Cmd/Ctrl+A selects every note. From the grid or a note, Cmd/Ctrl+D repeats the selection right after itself, Cmd/Ctrl+C, X and V copy, cut and paste at the playback position, and Q snaps the starts of the selection (every note, with none selected) to the grid. Renders a <div> element.

Row

The band a pitch takes across the grid, for shading black-key rows, the rows of the roll's scale, or ruling where an octave starts. It lets presses through to the grid and is hidden from assistive technology. Renders a <div> element.

Props · 1

Data attributes · 7

data-active
Whether the pitch is sounding.
data-color
"black" or "white".
data-folded
Whether the roll is folded.
data-in-scale
Whether the pitch is in the roll's scale.
data-out-of-scale
Whether the roll has a scale and the pitch is not in it.
data-scale-root
Whether the pitch is the root of the roll's scale: a C in C major.
data-octave
Whether the row is a C, where an octave starts.

Notes

Renders children once per note, in the order they are read: by start, then from the highest pitch down. That order is also the tab order. Renders no element of its own.

Props · 1

Note

One note, placed on its row from its start, as long as its length. A toggle button named after its pitch and span (getNoteLabel on Root). Its --piano-roll-velocity and --piano-roll-chance CSS variables are its velocity and how likely it is to play. Renders a <div> element.

Props · 1

Data attributes · 3

data-selected
Whether the note is in the selection: also aria-pressed.
data-muted
Whether the note is deactivated: it stays on the roll and does not play.
data-disabled
Present when disabled.

NoteHandle

One edge of the note it sits in, dragged to change the note's length: the end makes it longer or shorter, the start trims it from the front while its end stays put. On the grid unless Cmd/Ctrl is held, and for the whole selection when the note is part of it. Shift + Left and Right on the note do the same from the keyboard, so the handle is hidden from assistive technology. Renders a <div> element.

Props · 1

Marquee

The selection rectangle being dragged across the grid; renders nothing the rest of the time. Hidden from assistive technology. Renders a <div> element.

SelectionSpan

The time the selected notes cover, from the earliest start to the latest end, as a band from top to bottom of what it sits in: the grid, the velocity lane or the ruler. Renders nothing with no note selected. It lets presses through, all but its PianoRoll.StretchHandles, and is hidden from assistive technology. Renders a <div> element.

StretchHandle

One edge of the selection's span, for its SelectionSpan: a drag stretches the selected notes in time from the other edge, on the grid unless Cmd/Ctrl is held. The Notes edits that double and halve lengths do the same from the keyboard, so it is hidden from assistive technology. Renders a <div> element.

Props · 1

VelocityLane

A strip under the grid where each note's velocity, or with level="chance" its chance to play, stands as a bar placed at the note's start: a timeline lane, like the grid. In draw mode it is a brush: a drag across it sets every bar under the pointer, in the grid cell it is over, to the pointer's height. Put a PianoRoll.Velocity per note inside, with PianoRoll.Notes. Renders a <div> element.

Props · 1

Data attributes · 2

data-level
"velocity" or "chance".
data-mode
"draw" or "select": in draw mode the lane is a brush.

Velocity

One note's velocity, or its chance in a level="chance" lane, as a bar from the bottom of the lane: its height is the value, through the --piano-roll-level CSS variable. Dragging it up or down changes the value of the selection by the same amount when the note is part of it, so a phrase keeps its dynamics; Shift + click toggles the note in the selection. On a velocity bar, Cmd/Ctrl + drag sets how far the velocity may stray each time the note plays, its --piano-roll-deviation. A native <input type="range"> inside takes the arrow keys (Page Up/Down for larger steps, Home/End for none and full) and carries the accessible name, which defaults to the note's. The next drawn note gets the velocity set last. Renders a <div> element.

Props · 2

Data attributes · 2

data-selected
Whether the note is in the selection.
data-muted
Whether the note is deactivated.

Styled

The registry's styled Piano roll, its usage and interaction: Piano roll.

Built by Ouest Labs, the source code is available on GitHub.
RSS