EXEPERTAI LAB

Research alpha

Time Machine
EXEPERTAI LAB
GALLERY / COLLECTION
← Browse Astryx gallery
Chat·component·@astryxdesign/core

Chat Dictation Button

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

Open in Playground @astryxdesign/core/Chat

Showcases and examples

2 documented examples

Chat Dictation Button

Interactive dictation button connected to the SpeechRecognition API via useChatDictation. Click the mic to dictate into the composer.

Preview loads on approachPreview loads on approach
Exact source · chat-dictation-button-showcase
// Copyright (c) Meta Platforms, Inc. and affiliates.

'use client';

import {useRef} from 'react';
import {
  ChatDictationButton,
  ChatComposer,
  ChatComposerInput,
  useChatDictation,
} from '@astryxdesign/core/Chat';
import type {ChatComposerInputHandle} from '@astryxdesign/core/Chat';
import {HStack, VStack} from '@astryxdesign/core/Layout';
import {Text} from '@astryxdesign/core/Text';

export default function ChatDictationButtonShowcase() {
  const inputRef = useRef<ChatComposerInputHandle>(null);

  const dictation = useChatDictation({
    inputRef,
    hasSounds: true,
    onResult: text => {
      console.log('Dictation result:', text);
    },
  });

  return (
    <VStack gap={4} width={450} maxWidth="100%">
      <Text type="supporting" color="secondary">
        Click the microphone to start dictating. Speech is transcribed into the
        input.
      </Text>
      <ChatComposer
        onSubmit={v => console.log('Submit:', v)}
        input={<ChatComposerInput handleRef={inputRef} />}
        sendActions={<ChatDictationButton dictation={dictation} />}
      />
      {dictation.isListening && (
        <HStack gap={2} vAlign="center">
          <Text type="supporting" color="secondary">
            {dictation.isSpeaking ? 'Speaking detected' : 'Listening...'}
          </Text>
          <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>
        </HStack>
      )}
      {!dictation.isSupported && (
        <Text type="supporting" color="accent">
          SpeechRecognition is not supported in this browser.
        </Text>
      )}
    </VStack>
  );
}

Usage

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

  • Place the dictation button in the sendActions slot of ChatComposer so it sits next to the send button where users expect voice input controls.
  • Pass an inputRef to useChatDictation so interim transcripts appear as ghost text in the composer input while the user speaks.
  • Enable hasSounds on useChatDictation to give users audio feedback when dictation starts and stops. This is especially helpful when the button's visual change is subtle.
  • Don'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'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.

Typed props

PropType and behavior
dictationUseSpeechRecognitionReturn · required
The return value from useChatDictation or useSpeechRecognition. Controls all button state: listening, volume, bands, and toggle.
size'sm' | 'md' · default 'md'
Button size. Matches ChatComposer density.
isHiddenWhenUnsupportedboolean · default true
When true, renders nothing if the browser does not support SpeechRecognition. When false, keeps the button visible but disabled.
labelstring
Accessible label override. Defaults to "Start dictation" or "Stop dictation" based on state.
xstyleStyleXStyles
StyleX styles for layout customization (margins, positioning, sizing). Must be a stylex.create() value, not an inline style object like style={{}}.

Anatomy

Microphone icon · required

Shown in the idle state. Indicates that tapping will start voice input.

Frequency bars · optional

Animated equalizer bars that replace the icon during listening. React to real microphone volume.

Ghost button · required

The underlying Button with ghost variant and isIconOnly, providing the hit target and focus ring.