shadcn.io is not affiliated with official shadcn/ui
At rest it's a red dot on a quiet button. Press it and the dot squares off into a stop sign, a red fill grows in behind it and a ring keeps leaving the button's edge. Press again to stop. The pulse runs only while recording, so it says something is happening rather than asking for attention.
Use it for voice notes, video or screen recording, or a voice assistant's talk button; for a pulse that draws the eye at rest, use the Pulse Button. It keeps its own state; pass recording and onRecordingChange to start and stop a real recorder. It wraps the Button, so variant, size and pill work as usual, secondary by default. The dot and the fill change with CSS transitions and the ring is a CSS keyframe animation the install adds to your stylesheet, with no animation library; with reduced motion the ring is left out and the rest only fades.
Installation
Usage
import { RecordButton } from "@/components/ui/record-button";<RecordButton onRecordingChange={toggleRecorder} pill recording={recording}>
{elapsed}
</RecordButton>Demos
Variant
The red fill covers any variant while it records, so pick the one that suits the button at rest: here secondary, the default, then outline, destructive and ghost, the last one recording from the start with defaultRecording. Each icon-only button says what it records with startLabel.
Controlled
recording and onRecordingChange keep the state outside the button, where a real app starts and stops its MediaRecorder. This one counts the time while it records and lists the last clips.
Accessibility
Its name says what a press does, then the visible label: Start recording 0:00 at rest, Stop recording 0:12 while it records. Change the words with startLabel and stopLabel, not with an aria-label, which would hide them and the label. The dot, the fill and the ring are hidden from assistive tech. The label and the stop sign are drawn in the page's background color on the red fill, readable in light and dark.
- Enter
- Start or stop recording.
- Space
- Start or stop recording.
FAQ
How do I connect it to MediaRecorder?
Pass recording and onRecordingChange. Start the recorder when onRecordingChange gets true and stop it when it gets false. Leave recording out and the button keeps its own state, starting from defaultRecording.
Can it show the elapsed time?
Pass the time as its children, such as 0:12. The digits are tabular, so the width doesn't jump as the seconds tick, and the name reads Stop recording 0:12. The first demo does this.
Why does its name change when it records?
Because it says what a press does next: Start recording, then Stop recording. With a label of its own, such as Record screen, the name is Start recording Record screen; set startLabel to null to let the label speak alone.
How do I make it round?
Pass pill. Otherwise it takes the Button's radius, like every other button. With no children it's square, icon-lg; with children, lg.
Can I change its colors?
At rest it's the variant you pass, with a red dot. While recording, the fill, the ring and the dot use your theme's destructive color, so a theme with another red changes them all.
How is it different from Pulse Button?
Pulse Button pulses all the time to draw the eye. This one pulses only while it records, as a sign of activity.
API Reference
RecordButton
data-slot="record-button-state"
recording?boolean
Whether it's recording, to keep that state yourself. Pair it with
onRecordingChange.
defaultRecording?boolean
Whether it starts out recording, when you leave recording to the
button.
- Default
false
onRecordingChange?(recording: boolean) → void
Called with the new state each time the button is pressed.
- Parameters
recording– boolean- Returns
void
children?ReactNode
Text beside the dot, such as the elapsed time. Its digits are tabular, so a ticking clock doesn't shift.
focusableWhenDisabled?boolean
Whether the button should be focusable when disabled.
- Default
false
nativeButton?boolean
Whether the component renders a native <button> element when replacing it
via the render prop.
Set to false if the rendered element is not a button (for example, <div>).
- Default
true
startLabel?ReactNode
What the button says it does at rest, for screen readers, before the visible label.
- Default
"Start recording"
stopLabel?ReactNode
What the button says it does while recording, for screen readers, before the visible label.
- Default
"Stop recording"
render?ReactElement | ((props: object, state: object) => ReactElement)
Replace the host element or compose it with another component.
- Type
ReactElement | ((props: object, state: object) => ReactElement)
className?string
Merged with the part's classes.
data-state?string
"recording" when on is true, otherwise "idle".
Related
- Pro
Pulse Button
Motion & feedbackA pulse that runs all the time
- Pro
Long Press Button
ControlsHold to talk, release to stop
Icon Button
Hover revealsOther icon toggles with state
- Pro
Theme Toggle Button
ControlsAnother two-state toggle
- Pro
Success Button
Progress & resultsConfirm the clip was saved
Ripple Button
Motion & feedbackPress feedback from the touch point