Voice UI Kit
View source

DTMF Keypad

Telephone-style 12-key keypad for sending DTMF tones over a Pipecat session

The DTMF Keypad renders a standard 12-key telephone keypad for sending DTMF tones during a Pipecat session. It ships in two variants: a headless DTMFKeypadComponent with no SDK dependency and a connected DTMFKeypad that wires directly to the client via useDTMF.

Two dispatch modes are supported:

  • "buffered" (default): digits accumulate in an editable field and are sent as a single sequence when the user submits, so a mistyped digit can be corrected before anything is transmitted. Suited for dialing a full number or extension.
  • "immediate": each key press sends that tone right away. Suited for navigating live IVR menus where each key is answered on its own.

Local press feedback is synthesized from the standard DTMF frequency pairs using the Web Audio API, so no bundled audio assets are required. Feedback can be disabled with noToneFeedback.

import { DTMFKeypad } from "@pipecat-ai/voice-ui-kit";

<DTMFKeypad />

Component Variants

DTMFKeypad

The connected variant. Reads connection state via usePipecatConnectionState and dispatches tones via useDTMF from @pipecat-ai/client-react. The keypad is automatically disabled while the client is not connected. Must be used within a PipecatClientProvider context.

PropTypeDefault
mode?
"buffered" | "immediate"
"buffered"
variant?
ButtonVariant
"secondary"
size?
ButtonSize
"lg"
disabled?
boolean
false
noSubLabels?
boolean
false
noToneFeedback?
boolean
false
toneVolume?
number
0.15
buttonProps?
Partial<React.ComponentProps<typeof Button>>
undefined
placeholder?
string
"Enter digits"
sendLabel?
string
"Send"
classNames?
object
undefined
value?
string
undefined
defaultValue?
string
""
onValueChange?
(value: string) => void
undefined
onPress?
(button: DTMFButton) => void
undefined
onToneSent?
(sequence: string) => void
undefined
onError?
(error: unknown) => void
undefined

DTMFKeypadComponent

The headless variant. Holds no client state and can be used with any framework or state management solution. All dispatch callbacks are passed as props.

import { DTMFKeypadComponent } from "@pipecat-ai/voice-ui-kit";

function Demo() {
  const [sequence, setSequence] = React.useState("");

  return (
    <div className="flex flex-col gap-2 w-full max-w-xs">
      <div className="font-mono text-sm min-h-6">{sequence || " "}</div>
      <DTMFKeypadComponent
        mode="immediate"
        onPress={(key) => setSequence((s) => s + key)}
      />
    </div>
  );
}

render(<Demo />);
PropTypeDefault
mode?
"buffered" | "immediate"
"buffered"
variant?
ButtonVariant
"secondary"
size?
ButtonSize
"lg"
disabled?
boolean
false
noSubLabels?
boolean
false
noToneFeedback?
boolean
false
toneVolume?
number
0.15
buttonProps?
Partial<React.ComponentProps<typeof Button>>
undefined
placeholder?
string
"Enter digits"
sendLabel?
string
"Send"
classNames?
object
undefined
value?
string
undefined
defaultValue?
string
""
onValueChange?
(value: string) => void
undefined
onPress?
(button: DTMFButton) => void
undefined
onSend?
(sequence: string) => void
undefined

Usage

Buffered mode (default)

Digits accumulate in an editable field. The user can backspace to correct mistakes before pressing Send.

import { DTMFKeypad } from "@pipecat-ai/voice-ui-kit";

<DTMFKeypad
  onToneSent={(seq) => console.log("sent", seq)}
  onError={(err) => console.error("send failed", err)}
/>

Immediate mode

Each key sends its tone right away. Useful for navigating IVR menus.

import { DTMFKeypad } from "@pipecat-ai/voice-ui-kit";

<DTMFKeypad
  mode="immediate"
  onPress={(key) => console.log("pressed", key)}
  onToneSent={(key) => console.log("sent", key)}
/>

Headless in buffered mode

import { DTMFKeypadComponent } from "@pipecat-ai/voice-ui-kit";

<DTMFKeypadComponent
  onSend={(sequence) => {
    // send sequence to your backend
  }}
/>

Controlled buffer

import { DTMFKeypad } from "@pipecat-ai/voice-ui-kit";

const [digits, setDigits] = React.useState("");

<DTMFKeypad
  value={digits}
  onValueChange={setDigits}
  onToneSent={() => setDigits("")}
/>

Integration

DTMFKeypad uses:

  • usePipecatConnectionState to gate the keypad until the client is connected
  • useDTMF from @pipecat-ai/client-react, whose sendTone sends the digits over the transport

It must be used within a PipecatClientProvider context.

DTMFKeypadComponent has no SDK dependency and can be used standalone.

See Also

  • Console Template - The Console template exposes noDTMF and keypadMode props to show or hide the keypad toggle in its header

Changelog

v0.12.0
  • Added DTMFKeypad (connected) and DTMFKeypadComponent (headless) components.
  • Added DTMFKeypadMode type ("buffered" | "immediate").
  • Added DTMFKeypadBaseProps, DTMFKeypadProps, and DTMFKeypadComponentProps interfaces.