audiocn

Tempo Control

An editable BPM input with tap tempo, keyboard stepping and a rolling average.

Installation

$ pnpm dlx shadcn@latest add @audiocn/tempo-control

Usage

import { TempoControl } from "@/components/ui/tempo-control";
<TempoControl defaultValue={120} onValueChange={setBpm} />

Tap at least twice to measure a tempo. The control averages the last four intervals and starts a new sequence after more than two seconds without a tap. Typing or stepping the input clears the tap history.

BPM values are always whole numbers. Tapped, typed and externally supplied fractional values round to the nearest integer. The default range is 30-600 BPM; set min and max to suit your application.

Anatomy

The input and tap button render by default. Supply children to arrange the parts, change their labels, or omit the tap button.

<TempoControl>
  <TempoControlInput />
  <TempoControlTap>Tap tempo</TempoControlTap>
</TempoControl>

Examples

Custom elements

128 BPM

Use TempoControlTap's render prop to replace the default trigger with a custom element. This example combines a sound pad with a tempo readout.

Controlled BPM

Beat duration: 625 ms

value remains owned by the parent. onValueChange reports changes with a reason of tap, keyboard or input. onValueCommitted fires after a measured tap, keyboard step, or text edit committed by blurring the input.

Sizes and disabled states

Small
Large
Disabled
Read-only

size and disabled inherit from AudioConfigProvider; explicit props win. readOnly keeps the input focusable but prevents editing and tapping.

Theming

Variable or attributeMeaning
--tempo-heightShared input and tap-button height, set by size
data-sizesm, default or lg, on the root
data-disabledDisabled state, on the root
data-readonlyRead-only state, on the root
data-slottempo-control, tempo-control-input-group, tempo-control-input, tempo-control-unit, tempo-control-tap

Use className on the root, input and tap button to customize the layout and appearance. Colours follow the standard shadcn theme tokens.

Accessibility

  • The input is labelled "Tempo in beats per minute". Override aria-label, supply aria-labelledby, or pair id with a visible label and remove the default with aria-label={undefined}.
  • Space and Enter activate the focused tap button.
  • Disabled and read-only controls ignore taps. Holding a key does not generate repeated taps.
  • Press feedback respects reduced-motion preferences.
<label htmlFor="delay-tempo">Delay tempo</label>
<TempoControl>
  <TempoControlInput id="delay-tempo" aria-label={undefined} />
  <TempoControlTap />
</TempoControl>
FocusKeyAction
InputUp / DownChange by 1 BPM
InputShift + Up / DownChange by largeStep
InputHome / EndSet min / max
Tap buttonSpace / EnterTap once

API reference

TempoControl

Prop

Type

TempoControlInput

Accepts Base UI NumberField.Input props, including id, aria-label, className and ref.

TempoControlTap

Accepts Base UI Button props, including render, children, className, ref and disabled. A disabled or read-only root always disables tapping. An onClick handler can cancel a tap with event.preventDefault().