Voicemails
Display a list of voicemails with audio playback, transcription, and action buttons.
Basic Usage
import { Voicemails } from '@dialstack/sdk';
function Dashboard() {
return <Voicemails userId="user_123" />;
}
Required Prop
The userId prop is required. Without it, the component will display an error state.
Automatic Pagination
Pagination is handled automatically by the component using cursor-based pagination. The component automatically loads more voicemails as users scroll or interact with the list. See the Pagination Guide for details.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
userId | string | Required | User ID to fetch voicemails for |
locale | Locale | English | Custom locale for UI strings |
formatting | FormattingOptions | - | Date/phone formatting options |
icons | ComponentIcons | - | Custom SVG icons |
layoutVariant | 'compact' | 'comfortable' | 'default' | 'default' | Layout density |
classes | VoicemailsClasses | - | Custom CSS classes |
displayOptions | VoicemailDisplayOptions | - | Show/hide UI elements |
behaviorOptions | VoicemailBehaviorOptions | - | Playback and interaction behavior |
customRowRenderer | (voicemail) => string | - | Custom row rendering |
onLoaderStart | (event) => void | - | Loading started callback |
onLoadError | (event) => void | - | Loading failed callback |
onVoicemailSelect | (event) => void | - | Voicemail selected callback |
onVoicemailPlay | (event) => void | - | Playback started callback |
onVoicemailPause | (event) => void | - | Playback paused callback |
onVoicemailDelete | (event) => void | - | Voicemail deleted callback |
onCallBack | (event) => void | - | Call back button clicked |
onDeleteRequest | (id) => Promise<boolean> | - | Custom delete confirmation |
Display Options
Control which UI elements are visible:
<Voicemails
userId="user_123"
displayOptions={{
showDuration: true, // Show voicemail duration
showTranscription: true, // Show transcription when available
showCallbackButton: true, // Show call back button
showDeleteButton: true, // Show delete button
showProgressBar: true, // Show playback progress bar
showTimestamp: true, // Show received timestamp
}}
/>
VoicemailDisplayOptions
| Option | Type | Default | Description |
|---|---|---|---|
showDuration | boolean | true | Display voicemail length |
showTranscription | boolean | true | Show transcription text |
showCallbackButton | boolean | true | Enable call back action |
showDeleteButton | boolean | true | Enable delete action |
showProgressBar | boolean | true | Show audio progress bar |
showTimestamp | boolean | true | Display received time |
Behavior Options
Control playback and interaction behavior:
<Voicemails
userId="user_123"
behaviorOptions={{
autoPlayOnExpand: true, // Auto-play when expanded
confirmBeforeDelete: true, // Show delete confirmation
markAsReadOnPlay: true, // Mark as read when played
allowSeeking: true, // Allow seeking in audio
}}
/>
VoicemailBehaviorOptions
| Option | Type | Default | Description |
|---|---|---|---|
autoPlayOnExpand | boolean | true | Start playback when expanding |
confirmBeforeDelete | boolean | true | Show confirmation dialog |
markAsReadOnPlay | boolean | true | Mark as read on first play |
allowSeeking | boolean | true | Enable seeking in progress bar |
Callbacks
onVoicemailSelect
Triggered when a voicemail is expanded:
<Voicemails
userId="user_123"
onVoicemailSelect={(event) => {
console.log('Selected voicemail:', event.voicemailId);
}}
/>
onVoicemailPlay / onVoicemailPause
Track playback state:
<Voicemails
userId="user_123"
onVoicemailPlay={(event) => {
analytics.track('voicemail_played', { id: event.voicemailId });
}}
onVoicemailPause={(event) => {
analytics.track('voicemail_paused', { id: event.voicemailId });
}}
/>
onCallBack
Handle call back button clicks:
<Voicemails
userId="user_123"
onCallBack={(event) => {
// Initiate call to the number
initiateCall(event.phoneNumber);
}}
/>
onVoicemailDelete
Triggered after a voicemail is deleted:
<Voicemails
userId="user_123"
onVoicemailDelete={(event) => {
showToast('Voicemail deleted');
}}
/>
onDeleteRequest
Custom delete confirmation logic:
<Voicemails
userId="user_123"
onDeleteRequest={async (voicemailId) => {
// Show custom confirmation dialog
const confirmed = await showConfirmDialog({
title: 'Delete Voicemail',
message: 'Are you sure? This cannot be undone.',
});
return confirmed; // Return true to proceed, false to cancel
}}
/>
Custom Styling
CSS Classes
Apply custom classes:
<Voicemails
userId="user_123"
classes={{
base: 'rounded-lg shadow',
loading: 'animate-pulse',
error: 'border-red-500',
empty: 'text-gray-400 p-8',
list: 'divide-y',
item: 'p-4 hover:bg-gray-50',
itemExpanded: 'bg-gray-50',
itemUnread: 'border-l-4 border-blue-500',
player: 'mt-2',
actions: 'flex gap-2 mt-2',
}}
/>
VoicemailsClasses
| Class | Default | Description |
|---|---|---|
base | 'dialstack-component' | Container element |
loading | 'dialstack-component--loading' | Loading state |
error | 'dialstack-component--error' | Error state |
empty | 'dialstack-component--empty' | No voicemails state |
list | 'dialstack-voicemail-list' | List container |
item | 'dialstack-voicemail-item' | Voicemail item |
itemExpanded | 'dialstack-voicemail-item--expanded' | Expanded item |
itemUnread | 'dialstack-voicemail-item--unread' | Unread item |
player | 'dialstack-voicemail-player' | Audio player |
actions | 'dialstack-voicemail-actions' | Action buttons |
Layout Variants
<Voicemails userId="user_123" layoutVariant="compact" />
<Voicemails userId="user_123" layoutVariant="default" />
<Voicemails userId="user_123" layoutVariant="comfortable" />
Voicemail Data Model
interface Voicemail {
id: string;
from_name: string;
from_number: string;
created_at: string;
duration_seconds: number;
is_read: boolean;
transcription?: string;
}
Complete Example
import { Voicemails } from '@dialstack/sdk';
import { useCallback, useState } from 'react';
function VoicemailInbox({ userId }: { userId: string }) {
const [lastPlayed, setLastPlayed] = useState<string | null>(null);
const handleCallBack = useCallback((event: { phoneNumber: string }) => {
// Open phone dialer or initiate WebRTC call
window.location.href = `tel:${event.phoneNumber}`;
}, []);
const handleDeleteRequest = useCallback(async (voicemailId: string) => {
const confirmed = window.confirm('Are you sure you want to delete this voicemail?');
return confirmed;
}, []);
return (
<div className="max-w-2xl mx-auto">
<h1 className="text-2xl font-bold mb-4">Voicemails</h1>
<Voicemails
userId={userId}
layoutVariant="comfortable"
displayOptions={{
showDuration: true,
showTranscription: true,
showCallbackButton: true,
showDeleteButton: true,
showProgressBar: true,
showTimestamp: true,
}}
behaviorOptions={{
autoPlayOnExpand: true,
confirmBeforeDelete: false, // Use custom handler
markAsReadOnPlay: true,
allowSeeking: true,
}}
formatting={{
defaultCountry: 'US',
dateLocale: 'en-US',
use24HourTime: false,
}}
classes={{
base: 'bg-white rounded-lg shadow-lg',
list: 'divide-y divide-gray-200',
item: 'p-4 cursor-pointer transition-colors',
itemExpanded: 'bg-blue-50',
itemUnread: 'border-l-4 border-blue-500 bg-blue-50/50',
}}
onVoicemailSelect={(event) => {
console.log('Selected:', event.voicemailId);
}}
onVoicemailPlay={(event) => {
setLastPlayed(event.voicemailId);
}}
onCallBack={handleCallBack}
onDeleteRequest={handleDeleteRequest}
onVoicemailDelete={(event) => {
console.log('Deleted:', event.voicemailId);
}}
onLoadError={(event) => {
console.error('Load error:', event.error);
}}
/>
</div>
);
}
Accessibility
The Voicemails component includes:
- ARIA labels for all interactive elements
- Keyboard navigation (Tab, Enter, Space)
- Focus management when expanding/collapsing items
- Screen reader announcements for state changes
- Visible focus indicators