Push to Talk
A hold-to-talk key for radios, voice notes and walkie-talkie chat. Live exactly while held, by pointer, keyboard or a global key, with a halo everyone reads as on air and a shake for a press too short to send.
Installation#
Usage#
import { PushToTalk } from "@/components/ui/push-to-talk"
export function Example() {
return (
<PushToTalk
aria-label="Talk to the channel"
onTalkStart={() => recorder.start()}
onTalkEnd={() => recorder.send()}
onTalkCancel={() => recorder.discard()}
/>
)
}Shapes#
circle (the default) is the icon alone, for a console where the key sits beside other controls; name it with aria-label and show that name in a Tooltip. pill says it in words and, while live, counts the time on air. Hold each one.
Sizes#
md (the default) is 40px, the hit target on its own; lg is 48px, for the main control of a console or a phone's bottom bar. The glyph steps up with it.
Variants#
The idle paint. neutral (the default) is the ink solid: a transmit key is a tool, not a brand moment. primary takes the brand, for a product whose main action is talking. Live is the same for both: the destructive fill and the halo.
Minimum duration#
A press shorter than minDuration (450ms by default) is a slip, not a message. It fires onTalkCancel instead of onTalkEnd, both with the duration, and the control shakes. Here the minimum is 600ms.
Global shortcut#
shortcut makes a key transmit while held anywhere on the page, the way a radio console works. It stands down while focus is in a text field, while a modifier is held and while a dialog the control is not in is open. The key also lands in aria-keyshortcuts.
Labels and icons#
label and liveLabel set the words; timer={false} drops the count. icon and liveIcon swap the glyphs, which cross-fade on the live state.
Disabled#
disabled dims the control and turns its shortcut off. Disabling it while live ends the hold.
API reference#
PushToTalk
A <button> with aria-pressed and data-state="idle" | "live". Props: shape (circle · pill), size (md · lg), variant (neutral · primary), label, liveLabel, timer, icon, liveIcon, minDuration, shortcut, disabled, and the callbacks onTalkStart(), onTalkEnd(ms), onTalkCancel(ms) and onTalkingChange(talking). Every button prop is forwarded; className is merged last.