A piano keyboard for a MIDI pitch range, played with the pointer, touch or the keyboard.
Base UI
import { Piano } from "@/components/audio/elements/piano";
export function PianoSizeDefaultDemo() {Plays or shows notes, for a virtual instrument, a MIDI visualizer or a chord reference. The registry component wraps the Piano primitive from @audio-ui/react and draws white and black keys for any MIDI range.
minPitch and maxPitch are MIDI pitches (default 48 and 72, C3 to C5), or pitches lists the exact keys to show. Key colors and layout follow the chromatic pattern.onNoteOn(pitch, eventDetails) and onNoteOff(pitch, eventDetails) report MIDI pitches, ready for an audio engine. eventDetails.reason says how the note started ("press", "glide" or "keyboard"), and eventDetails.cancel() in onNoteOn keeps the key silent.activeNotes lights keys from outside, such as a MIDI input or a sequencer's current chord, without calling onNoteOn or onNoteOff.orientation="vertical", lowest key at the bottom) or in equal widths (layout="even"). The piano roll's keyboard uses this.Import the primitive and assemble its parts.
import { Piano } from "@audio-ui/react";
<Piano.Root>
<Piano.Keys>
{(pitch) => (
<Piano.Key pitch={pitch}>
<Piano.KeyLabel />
</Piano.Key>
)}
</Piano.Keys>
</Piano.Root>import { Piano } from "@/components/audio/piano";Note events:
<Piano
maxPitch={72}
minPitch={48}
onNoteOff={(pitch) => synth.release(pitch)}
onNoteOn={(pitch) => synth.trigger(pitch)}
/>External notes (MIDI input, a sequencer's current chord):
<Piano activeNotes={midiInputNotes} maxPitch={72} minPitch={48} />Behavior · 4
onNoteOn; the key stays pressed while held.onNoteOff.onNoteOff) and the next one sounds (onNoteOn) as the pointer crosses it.The keys share one tab stop. On the focused key:
Keys · 4
onNoteOn on press, onNoteOff on releaseA keyboard to play: every key sounds while pressed, by pointer or from the keyboard. Dragging across the keys glides from one to the next, and each pointer holds its own key, so chords can be played on a touch screen. It is laid out like a piano, or with layout="even" as one equal share per key, the way a piano roll's rows are; orientation="vertical" puts the low end at the bottom. The keys are one tab stop, walked with the arrow keys. Renders a <div> element.
Props · 9
eventDetails.cancel() keeps it silent.minPitch…maxPitch.Data attributes · 1
data-disabledRenders children once per key, lowest first: the place to put a Piano.Key for each pitch. Renders no element of its own.
Props · 1
One key, placed along the keyboard for its pitch. It sounds while pressed: by pointer through the keyboard, or with Enter or Space while focused. Its accessible name defaults to the pitch, such as "C4". Renders a <button> element.
Props · 1
Data attributes · 2
data-activeactiveNotes.data-disabledThe name of the key it sits in, such as "C4". Hidden from assistive technology, which reads the key's own name. Renders a <span> element.
Data attributes · 1
data-disabledPiano accepts style props (size, className) plus primitive props from PianoPrimitive.Root.Props.
Props · 9
minPitch…maxPitch.eventDetails.cancel() keeps it silent.Props · 2
Additional valid HTML attributes passed to Piano.Root are forwarded.
Base UI
"use client";
import { useEffect, useState } from "react";