XDSChatDictationButton@xds/core · Chat

Usage

ChatDictationButton is a toggle button that starts and stops voice dictation inside a chat composer. It pairs with useXDSChatDictation to show a microphone icon when idle and animated frequency bars when listening. Place it in the sendActions slot of XDSChatComposer.

Best practices

GuidancePractices
DoPlace the dictation button in the sendActions slot of XDSChatComposer so it sits next to the send button where users expect voice input controls.
DoPass an inputRef to useXDSChatDictation so interim transcripts appear as ghost text in the composer input while the user speaks.
DoEnable hasSounds on useXDSChatDictation to give users audio feedback when dictation starts and stops — especially helpful when the button's visual change is subtle.
Don'tDon't use the dictation button outside a chat composer context — it's designed for the composer's send-action layout, not as a standalone recording control.
Don'tDon't forget to handle the unsupported case — the button hides itself by default when the browser lacks SpeechRecognition, but you should still design the composer to work without it.

Anatomy

ElementDescription
Microphone iconrequiredShown in the idle state. Indicates that tapping will start voice input.
Frequency barsAnimated equalizer bars that replace the icon during listening. React to real microphone volume.
Ghost buttonrequiredThe underlying XDSButton with ghost variant and isIconOnly, providing the hit target and focus ring.

Import

ts
import {XDSChatDictationButton} from '@xds/core/Chat'

Props

PropTypeDescription
dictationrequired
UseSpeechRecognitionReturnThe return value from useXDSChatDictation or useSpeechRecognition. Controls all button state — listening, volume, bands, and toggle.
size
'sm' | 'md' (default: 'md')Button size. Matches XDSChatComposer density.
isHiddenWhenUnsupported
boolean (default: true)When true, renders nothing if the browser does not support SpeechRecognition.
label
stringAccessible label override. Defaults to "Start dictation" or "Stop dictation" based on state.
xstyle
StyleXStylesStyleX styles for layout customization (margins, positioning, sizing). Must be a stylex.create() value — not an inline style object like style={{}}.

Showcase source

tsx
'use client';
import {useRef} from 'react';
import {
XDSChatDictationButton,
XDSChatComposer,
XDSChatComposerInput,
useXDSChatDictation,
} from '@xds/core/Chat';
import type {XDSChatComposerInputHandle} from '@xds/core/Chat';
import {XDSHStack, XDSVStack} from '@xds/core/Layout';
import {XDSText} from '@xds/core/Text';
export default function ChatDictationButtonShowcase() {
const inputRef = useRef<XDSChatComposerInputHandle>(null);
const dictation = useXDSChatDictation({
inputRef,
hasSounds: true,
onResult: (text) => {
console.log('Dictation result:', text);
},
});
return (
<XDSVStack gap={4}>
<XDSText type="supporting" color="secondary">
Click the microphone to start dictating. Speech is transcribed into the
input.
</XDSText>
<XDSChatComposer
onSubmit={(v) => console.log('Submit:', v)}
input={<XDSChatComposerInput ref={inputRef} />}
sendActions={<XDSChatDictationButton dictation={dictation} />}
/>
{dictation.isListening && (
<XDSHStack gap={2} vAlign="center">
<XDSText type="supporting" color="secondary">
{dictation.isSpeaking ? 'Speaking detected' : 'Listening...'}
</XDSText>
<div
style={{
width: 80,
height: 6,
backgroundColor: 'var(--color-surface-secondary)',
borderRadius: 3,
overflow: 'hidden',
}}>
<div
style={{
height: '100%',
backgroundColor: dictation.isSpeaking
? 'var(--color-accent)'
: 'var(--color-text-secondary)',
borderRadius: 3,
transition: 'width 0.08s ease-out',
width: `${Math.min(dictation.volume * 200, 100)}%`,
}}
/>
</div>
</XDSHStack>
)}
{!dictation.isSupported && (
<XDSText type="supporting" color="active">
SpeechRecognition is not supported in this browser.
</XDSText>
)}
</XDSVStack>
);
}