DAW transport controls: play, pause and stop, the position in bars, beats and sixteenths, loop and metronome toggles, tempo and time signature.
Base UI
"use client";
import { createSource } from "@audio-ui/react";import { Transport } from "@/components/audio/elements/transport";
<Transport
looping={looping}
metronome={metronome}
onLoopingChange={setLooping}
onMetronomeChange={setMetronome}
onPlayPause={() => (playing ? engine.pause() : engine.play())}
onStop={() => engine.stop()}
onTempoChange={setTempo}
playing={playing}
source={position} // seconds, a live value
tempo={tempo} // { bpm, beatsPerBar, beatUnit }
/>;The bar has three clusters, with gaps between them and none inside them: play or pause (the one filled button), stop and the position; the loop and the metronome; the tempo and the time signature. The position is three labelled figures, bar, beat and 16th, counted from tempo and written to the page as source moves, so a playing transport does not re-render. Loop and metronome are filled when on and outlined when off (aria-pressed), so the state is not carried by color alone; the metronome's two dots take the beat in turn. The tempo is a number field: type it and press Enter, step it with the arrow keys and the Page keys, or drag the BPM unit sideways to scrub it; the wheel never changes it. The loop, the metronome and the tempo clusters show only when you give their handlers.
When the transport is narrower than 42rem, it folds what does not fit into one menu. The tempo becomes a button that reads "120 BPM"; its menu holds the tempo field, a Loop switch, a Metronome submenu (its On switch and the rhythms), and the time signature. Loop and metronome leave the bar at that width. The fold depends on the transport's width, not the page's, so it works wherever the transport is placed. The transport takes the room left beside the controls it sits with, because a container query needs a definite width.
The bar is a toolbar: it takes one tab stop, and the arrow keys move between its buttons, the metronome's menu and the time signature.
Give onRhythmChange and a caret beside the metronome opens a menu of how often it clicks: with the beat ("auto"), or a bar, a half, a quarter, an eighth, a sixteenth, each straight or as a triplet. Rhythms are named from the interval they work out to, through the same gridLabel the timeline's grid uses, so 1/8T means one thing in both. The metronome's dots follow the rhythm, so they and the click are one pulse. Give onSoundChange with sounds ({ value, label }[]) and sound to list sounds in the same menu.
Props · 9
onSoundChange is given.Browse 1 production-ready audio/ui Transport components for players, mixers, and synth interfaces. These examples use Base UI primitives from @base-ui/react and stay fully compatible with Shadcn Create so radius, color, and typography match your configured theme.
Browse all 1 Shadcn Transport components for copy-ready layouts, dashboards, and forms built with Tailwind CSS in the audio/ui library.