Skip to content
WANCRAFT

A.185Buttons & Controls

Record Button

A voice-note record button: the circle morphs into a stop square, a ring pulses with the level, then play back or discard.

NewReactMotionSVGTailwindadvanced

Overview

Record Button walks through the whole voice-note flow in one compact pill. Idle, it is a round button with a record dot. Press it and the dot springs into a rounded stop square, a ring around the button breathes with the input level, a timer runs and a hairline fills toward the maximum length, where recording stops on its own. Stop, and the button becomes a play control beside a waveform of what you recorded, with the played portion tinted as it plays, plus discard and done. Simulated mode, the default, fakes a speech-like level and needs no permission, so the demo and catalogue never prompt. Microphone mode calls getUserMedia only when the user presses record, reads the level from a Web Audio analyser, records with MediaRecorder, hands the Blob to onRecorded, explains a blocked or missing microphone in plain words, and stops every track on stop and on unmount.

01Installation

Method 01 · Registry

CLI verified

Uses the shadcn CLI in a project initialised with shadcn init. Installs the file to components/ui/record-button.tsx and adds its dependencies.

npx shadcn@latest add https://wancraft.my/r/record-button.json

Method 02 · Copy and paste

  1. 1. Install the dependencies below.
  2. 2. Copy the source from the Code tab into components/ui/record-button.tsx.
  3. 3. Import it and adjust props.
npm install motion
Dependencies
motion
Peer
react ≥ 18, tailwindcss ≥ 4
Added
13 Oct 2026
Updated
—

02Usage

The default configuration. Change properties above to generate a tailored example in the Usage tab.

example.tsx
import { RecordButton, type RecordButtonResult } from "@/components/ui/record-button";

export function RecordButtonExample() {
  const keep = (result: RecordButtonResult) => {
    // result.blob is null in simulated mode
    console.log(result.duration, result.blob);
  };

  return (
    <RecordButton onDone={keep} />
  );
}

03Props

PropTypeDefaultDescription
mode"simulated" | "microphone""simulated"Simulated fakes the level with no permission. Microphone calls getUserMedia on the first press only.
maxDurationnumber60Seconds before recording stops automatically.
labelstring"Voice note"Visible title; names the group and the record button.
pulsebooleantrueThe ring around the button follows the input level.
sensitivitynumber1Gain applied to the level meter.
size"sm" | "md" | "lg""md"Main button size: 44, 56 or 68 px.
accentstring"#FF7448"Record glyph, level ring, played waveform and focus ring colour.
onRecordingStart() => void—Recording has started (after permission in microphone mode).
onRecorded(result: RecordButtonResult) => void—A recording stopped. result = { blob, duration, mimeType }; blob is null in simulated mode.
onDone(result: RecordButtonResult) => void—The user kept the recording with Done.
onDiscard() => void—The user discarded the recording.
...propsHTMLAttributes<HTMLDivElement>—Forwarded to the root group.

04Features

  • 01Idle → recording → recorded flow in one pill, with spring morphs between states
  • 02Record dot morphs into a rounded stop square; a ring pulses with the input level
  • 03Elapsed timer, progress hairline and automatic stop at the maximum length
  • 04Playback with a recorded waveform whose played portion is tinted (clip-path, no per-frame renders)
  • 05Simulated mode for demos; microphone mode with getUserMedia, Web Audio level and MediaRecorder Blob
  • 06Clear messages for blocked, missing or busy microphones; tracks stop on stop and unmount
motion · springmotion · continuousinput · clickinput · pressinput · keyboardinput · focus

05Accessibility

  • The record control is a native button named "Record voice note" with aria-pressed reflecting recording; Space or Enter starts and stops it.
  • A polite live region announces "Recording started", "Recording stopped, 0:12", discards, completion and microphone errors.
  • When the record button turns into the play button (and back), focus moves to the replacement so keyboard users never lose their place.
  • Play / pause, discard and done are labelled buttons with visible focus rings; the waveform and level ring are aria-hidden.
  • No permission is ever requested on load; microphone access is requested only by pressing record in microphone mode.
  • Reduced motion: no morph spring or pulsing; the ring is shown static while recording.

06Limitations

  • Microphone mode needs a secure context and MediaRecorder support; the recorded format (usually WebM or MP4/AAC) is chosen by the browser.