import { MessageInput } from "stream-chat-react";
const Composer = () => <MessageInput audioRecordingEnabled />;Audio Recorder
Enable audio recording on MessageInput to let users record voice messages.
Once enabled, the composer renders StartRecordingAudioButton. When recording starts, MessageInputFlat swaps the normal composer UI for AudioRecorder.
Best Practices
- Enable recording only where voice messages make sense for the product.
- Use
asyncMessagesMultiSendEnabledif users should be able to combine text, attachments, and voice recordings before sending. - Customize recording UI through
WithComponents, not deadChanneloverride props. - Keep permission-denied messaging short and actionable.
- Test both immediate-send and stacked-send behavior when changing recording flows.
UI Customization
The default recording surfaces are provided through ComponentContext:
StartRecordingAudioButtonAudioRecorderRecordingPermissionDeniedNotification
Use WithComponents to override them:
import { Channel, MessageInput, WithComponents } from "stream-chat-react";
const CustomStartRecordingAudioButton = (props) => (
<button {...props}>Record</button>
);
const CustomAudioRecorder = () => <div>Custom recorder UI</div>;
const CustomRecordingPermissionDeniedNotification = () => (
<div>Allow microphone access in your browser settings.</div>
);
const App = () => (
<WithComponents
overrides={{
AudioRecorder: CustomAudioRecorder,
RecordingPermissionDeniedNotification:
CustomRecordingPermissionDeniedNotification,
StartRecordingAudioButton: CustomStartRecordingAudioButton,
}}
>
<Channel>
<MessageInput audioRecordingEnabled />
</Channel>
</WithComponents>
);The custom components above are app-owned examples.
Browser Permissions
If microphone permission is denied when the user tries to start recording, the SDK opens a callout anchored to the recording button and renders RecordingPermissionDeniedNotification.
The default notification component receives only:
| Prop | Type |
|---|---|
permissionName | "microphone" | "camera" |
The close behavior is managed by the SDK dialog layer. Custom notification components do not receive an onClose callback.
Custom Encoding
By default, recordings are encoded as audio/wav. To reduce size, you can use the MP3 encoder plugin based on lamejs:
- Install
@breezystack/lamejs.
npm install @breezystack/lamejsyarn add @breezystack/lamejs- Pass the encoder through
audioRecordingConfig.
import { useMemo } from "react";
import { MessageInput } from "stream-chat-react";
import { encodeToMp3 } from "stream-chat-react/mp3-encoder";
const Composer = () => {
const audioRecordingConfig = useMemo(
() => ({ transcoderConfig: { encoder: encodeToMp3 } }),
[],
);
return (
<MessageInput
audioRecordingConfig={audioRecordingConfig}
audioRecordingEnabled
/>
);
};Sending Behavior
The recording uploads when recording is completed.
Sending behavior is controlled by asyncMessagesMultiSendEnabled on MessageInput:
asyncMessagesMultiSendEnabled | Behavior |
|---|---|
false | uploads and sends the voice recording immediately |
true | keeps the voice recording in the composer preview stack until the user submits the whole composition |
When a recording stays in the composer, it is rendered in the dedicated VoiceRecordingPreviewSlot.
Recording Controller
Components consuming MessageInputContext can read recorder state through recordingController:
import { useMessageInputContext } from "stream-chat-react";
const RecorderStatus = () => {
const {
recordingController: {
completeRecording,
permissionState,
recorder,
recording,
recordingState,
},
} = useMessageInputContext();
return (
<pre>
{JSON.stringify(
{
hasRecorder: !!recorder,
permissionState,
recordingState,
hasRecording: !!recording,
},
null,
2,
)}
</pre>
);
};The controller exposes:
| Property | Description |
|---|---|
completeRecording | stops recording and finalizes the voice attachment |
permissionState | current browser permission state |
recorder | media-recorder controller instance |
recording | generated voice-recording attachment after stop |
recordingState | current recording lifecycle state |