Tailor speak-mintlify to match your documentation’s unique needs and branding.
Audio Component Customization
The audio player component is fully customizable. Start with the provided template and modify it to match your design system.
Component Configuration
Specify your custom component in speaker-config.yaml:
component :
import : /snippets/audio-transcript.jsx # Path to your component
name : AudioTranscript # Component name
The import path is relative to your documentation root.
Component Props Interface
Your component receives this props structure:
interface AudioTranscriptProps {
voices : Array <{
name : string ; // Display name (from speaker-config.yaml)
url : string ; // S3 public URL to audio file
}>;
}
Example: Minimal Player
Create a simple, lightweight audio player:
/snippets/minimal-audio.jsx
export const MinimalAudio = ({ voices = [] }) => {
const audioUrl = voices [ 0 ]?. url ;
if ( ! audioUrl ) return null ;
return (
< div className = "my-4 p-4 border rounded-lg" >
< div className = "flex items-center gap-3" >
< svg className = "w-5 h-5" fill = "currentColor" viewBox = "0 0 20 20" >
< path d = "M10 12a2 2 0 100-4 2 2 0 000 4z" />
< path fillRule = "evenodd" d = "M.458 10C1.732 5.943 5.522 3 10 3s8.268 2.943 9.542 7c-1.274 4.057-5.064 7-9.542 7S1.732 14.057.458 10zM14 10a4 4 0 11-8 0 4 4 0 018 0z" clipRule = "evenodd" />
</ svg >
< audio controls className = "flex-1" src = { audioUrl } >
Your browser does not support audio playback.
</ audio >
</ div >
</ div >
);
};
Update config:
component :
import : /snippets/minimal-audio.jsx
name : MinimalAudio
Example: Multi-Voice Tabs
Display voices as tabs instead of a dropdown:
/snippets/tabbed-audio.jsx
import { useState } from 'react' ;
export const TabbedAudio = ({ voices = [] }) => {
const [ activeTab , setActiveTab ] = useState ( 0 );
if ( voices . length === 0 ) return null ;
return (
< div className = "border rounded-lg overflow-hidden" >
{ /* Tabs */ }
{ voices . length > 1 && (
< div className = "flex bg-gray-100 dark:bg-gray-800" >
{ voices . map (( voice , idx ) => (
< button
key = { idx }
onClick = { () => setActiveTab ( idx ) }
className = { `px-4 py-2 text-sm font-medium transition-colors ${
idx === activeTab
? 'bg-white dark:bg-gray-900 text-blue-600'
: 'text-gray-600 hover:text-gray-900'
} ` }
>
{ voice . name }
</ button >
)) }
</ div >
) }
{ /* Audio Player */ }
< div className = "p-4 bg-white dark:bg-gray-900" >
< audio
key = { voices [ activeTab ]. url }
controls
className = "w-full"
src = { voices [ activeTab ]. url }
>
Your browser does not support audio.
</ audio >
</ div >
</ div >
);
};
Example: Branded Player
Match your brand colors and style:
/snippets/branded-audio.jsx
export const BrandedAudio = ({ voices = [] }) => {
return (
< div className = "my-6 rounded-xl overflow-hidden shadow-lg bg-gradient-to-r from-purple-500 to-pink-500 p-0.5" >
< div className = "bg-white dark:bg-gray-900 rounded-xl p-6" >
< div className = "flex items-center gap-3 mb-4" >
< div className = "w-10 h-10 bg-gradient-to-r from-purple-500 to-pink-500 rounded-full flex items-center justify-center" >
< svg className = "w-6 h-6 text-white" fill = "currentColor" viewBox = "0 0 20 20" >
< path d = "M18 3a1 1 0 00-1.196-.98l-10 2A1 1 0 006 5v9.114A4.369 4.369 0 005 14c-1.657 0-3 .895-3 2s1.343 2 3 2 3-.895 3-2V7.82l8-1.6v5.894A4.37 4.37 0 0015 12c-1.657 0-3 .895-3 2s1.343 2 3 2 3-.895 3-2V3z" />
</ svg >
</ div >
< div >
< h4 className = "font-bold text-lg" > Listen to this page </ h4 >
< p className = "text-sm text-gray-600 dark:text-gray-400" > Choose your preferred voice </ p >
</ div >
</ div >
{ voices . map (( voice , idx ) => (
< div key = { idx } className = "mb-3 last:mb-0" >
< label className = "block text-sm font-medium mb-1" > { voice . name } </ label >
< audio controls className = "w-full" src = { voice . url } />
</ div >
)) }
</ div >
</ div >
);
};
File Pattern Customization
Custom File Patterns
Control which files get processed:
All MDX files (default)
Specific directory
Multiple patterns
Exclude patterns with .speakignore
npx speak-mintlify generate .
Using .speakignore
Create a .speakignore file at your repository root:
# Exclude API reference pages
api-reference/**
# Exclude reusable snippets
snippets/**
# Exclude legal pages
legal/**
terms.mdx
privacy.mdx
# Exclude drafts and work-in-progress
drafts/**
wip/**
*.draft.mdx
# Exclude changelog
CHANGELOG.md
release-notes/**
# Exclude specific files
index.mdx
404.mdx
Use .speakignore to reduce API costs by excluding pages that don’t benefit from audio narration.
Voice Configuration Strategies
Strategy 1: Single Professional Voice
Best for: Corporate docs, consistent brand voice
voices :
8ef4a238714b45718ce04243307c57a7 : Professional Narrator
Strategy 2: Multiple Personality Voices
Best for: Developer tools, friendly tone
voices :
8ef4a238714b45718ce04243307c57a7 : Sarah (Friendly)
bf322df2096a46f18c579d0baa36f41d : Adrian (Technical)
933563129e564b19a115bedd57b7406a : Alex (Casual)
Strategy 3: Multilingual Support
Best for: International audience
voices :
8ef4a238714b45718ce04243307c57a7 : English
a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6 : Español
b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7 : Français
c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8 : 日本語
Strategy 4: Role-Based Voices
Best for: Tutorial content, conversational docs
voices :
8ef4a238714b45718ce04243307c57a7 : Instructor
bf322df2096a46f18c579d0baa36f41d : Student Guide
933563129e564b19a115bedd57b7406a : Expert Tips
S3 Path Customization
Customize how audio files are organized in S3:
# Default: audio/
npx speak-mintlify generate .
# Result: s3://bucket/audio/page-slug/voice-id.mp3
# Custom prefix
npx speak-mintlify generate . --s3-path-prefix "tts"
# Result: s3://bucket/tts/page-slug/voice-id.mp3
# Versioned audio
npx speak-mintlify generate . --s3-path-prefix "audio/v2"
# Result: s3://bucket/audio/v2/page-slug/voice-id.mp3
Update in config:
voices :
8ef4a238714b45718ce04243307c57a7 : Main Voice
# This is a comment - CLI flag would be:
# --s3-path-prefix "custom-path"
S3 path prefix can only be set via CLI flag, not in speaker-config.yaml.
Advanced Workflows
Conditional Generation
Generate audio only for specific branches:
.github/workflows/tts-conditional.yaml
name : Conditional TTS
on :
push :
branches :
- main
- production
jobs :
generate :
runs-on : ubuntu-latest
steps :
- uses : actions/checkout@v4
- uses : actions/setup-node@v4
with :
node-version : '20'
# Generate for production with all voices
- name : Generate (production)
if : github.ref == 'refs/heads/production'
run : npx speak-mintlify generate .
env :
FISH_API_KEY : ${{ secrets.FISH_API_KEY }}
# ... other env vars
# Generate for main with single voice
- name : Generate (staging)
if : github.ref == 'refs/heads/main'
run : |
npx speak-mintlify generate . \
--voices "8ef4a238714b45718ce04243307c57a7" \
--voice-names "Preview Voice"
env :
FISH_API_KEY : ${{ secrets.FISH_API_KEY }}
# ... other env vars
Incremental Updates
Only process changed files:
.github/workflows/tts-incremental.yaml
name : Incremental TTS
on :
push :
paths :
- '**.mdx'
jobs :
generate :
runs-on : ubuntu-latest
steps :
- uses : actions/checkout@v4
with :
fetch-depth : 2
- uses : actions/setup-node@v4
- name : Get changed files
id : changed
run : |
echo "files=$(git diff --name-only HEAD~1 HEAD | grep '.mdx$' | tr '\n' ' ')" >> $GITHUB_OUTPUT
- name : Generate for changed files
if : steps.changed.outputs.files != ''
run : |
for file in ${{ steps.changed.outputs.files }}; do
npx speak-mintlify generate . --pattern "$file"
done
env :
FISH_API_KEY : ${{ secrets.FISH_API_KEY }}
# ... other env vars
speak-mintlify already tracks content hashes and only regenerates when content changes. This workflow is for advanced use cases with large documentation sets.
Multi-Environment Setup
Use different configurations for staging and production:
Development
Staging
Production
voices :
8ef4a238714b45718ce04243307c57a7 : Dev Voice
component :
import : /snippets/audio-dev.jsx
name : DevAudio
# Copy to speaker-config.yaml for local testing
cp speaker-config.dev.yaml speaker-config.yaml
npx speak-mintlify generate . --dry-run
speaker-config.staging.yaml
voices :
8ef4a238714b45718ce04243307c57a7 : Staging Voice
component :
import : /snippets/audio-transcript.jsx
name : AudioTranscript
voices :
8ef4a238714b45718ce04243307c57a7 : Professional Female
bf322df2096a46f18c579d0baa36f41d : Professional Male
933563129e564b19a115bedd57b7406a : Friendly Guide
component :
import : /snippets/audio-transcript.jsx
name : AudioTranscript
Styling and Theming
Tailwind CSS Integration
The default component uses Tailwind. Customize with your theme:
/snippets/audio-transcript.jsx
// Use your custom Tailwind classes
< div className = "border rounded-lg bg-card border-primary/20" >
< div className = "px-3 py-1.5 bg-primary/10" >
< span className = "text-sm font-semibold text-primary" > Listen </ span >
</ div >
{ /* ... */ }
</ div >
CSS Modules
For scoped styles:
/snippets/styled-audio.jsx
import styles from './audio.module.css' ;
export const StyledAudio = ({ voices = [] }) => {
return (
< div className = { styles . audioPlayer } >
< audio controls src = { voices [ 0 ]?. url } className = { styles . audioElement } />
</ div >
);
};
/snippets/audio.module.css
.audioPlayer {
padding : 1 rem ;
border : 2 px solid var ( --accent-color );
border-radius : 0.5 rem ;
background : var ( --bg-color );
}
.audioElement {
width : 100 % ;
accent-color : var ( --accent-color );
}
Dark Mode Support
Handle dark mode with Tailwind:
< div className = "bg-white dark:bg-gray-900 text-gray-900 dark:text-gray-100" >
< audio
controls
className = "w-full [&::-webkit-media-controls-panel]:bg-gray-100 dark:[&::-webkit-media-controls-panel]:bg-gray-800"
src = { voices [ 0 ]?. url }
/>
</ div >
Troubleshooting Customization
Check import path is correct in speaker-config.yaml
Verify file exists at specified path
Ensure component is exported (named export)
Check component name matches exactly (case-sensitive)
Props not passed correctly
Verify component accepts voices prop
Check prop structure matches interface
Use --verbose to see generated component code
Test component independently first
Ensure Tailwind processes your component file
Check CSS imports are working
Verify class names don’t conflict
Test in browser dev tools
File patterns not working
Test pattern with glob tool: npx glob "your-pattern"
Ensure pattern is quoted in CLI
Check .speakignore isn’t excluding files
Use --verbose to see matched files
Best Practices
Start with the default component
Modify the provided audio-transcript.jsx rather than building from scratch.
Test locally first
Use --dry-run to preview changes before generating audio.
Keep components simple
Focus on core functionality. Complex interactions can impact performance.
Support accessibility
Include ARIA labels, keyboard navigation, and screen reader support.
Optimize for mobile
Ensure audio player works well on touch devices.
Version your components
Track component changes in git for easy rollback.
Next Steps
CI/CD Integration Automate customized workflows
Fish Audio Configure voices for your custom player