
Syncfusion React Speech To Text
- 390 installs
- 3 repo stars
- Updated July 28, 2026
- syncfusion/react-ui-components-skills
syncfusion-react-speech-to-text is a Syncfusion Agent Skill that teaches developers to implement the React SpeechToText component for real-time voice transcription, microphone control, localization, and accessible form i
About
syncfusion-react-speech-to-text is a Syncfusion Agent Skill (version 33.1.44) for adding browser-based speech recognition to React apps via @syncfusion/ej2-react-inputs. The SKILL.md documents six reference guides on getting started, speech recognition features, button and tooltip customization, events and methods, globalization, and troubleshooting/security. Quick-start TSX wires SpeechToTextComponent transcriptChanged events to a TextAreaComponent for live voice notes. Patterns cover voice form inputs, programmatic startListening()/stopListening() via refs, and onError handling with human-readable errorMessage fields. Key props include lang, allowInterimResults, listeningState enum, and 12 TooltipPosition values. Developers reach for this skill when agents must generate correct Syncfusion speech components with microphone permission handling instead of generic Web Speech API snippets.
- syncfusion-react-speech-to-text
Syncfusion React Speech To Text by the numbers
- 390 all-time installs (skills.sh)
- +22 installs in the week ending Jul 27, 2026 (Skillselion tracking)
- Ranked #1,076 of 4,347 Backend & APIs skills by installs in the Skillselion catalog
- Data as of Jul 29, 2026 (Skillselion catalog sync)
npx skills add https://github.com/syncfusion/react-ui-components-skills --skill syncfusion-react-speech-to-textAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 390 |
|---|---|
| repo stars | ★ 3 |
| Last updated | July 28, 2026 |
| Repository | syncfusion/react-ui-components-skills ↗ |
How do you add voice input to a React form?
Use syncfusion-react-speech-to-text for development tasks
Who is it for?
React developers building voice-enabled forms or note-taking UIs with Syncfusion Essential Studio who need Web Speech API integration with proper event typing.
Skip if: Server-side transcription pipelines, mobile native speech SDKs, or projects not using Syncfusion React input components.
When should I use this skill?
The user asks to add Syncfusion speech-to-text, voice input buttons, microphone transcription, or accessible voice forms in React.
What you get
SpeechToTextComponent TSX with transcript handlers, tooltip config, ARIA attributes, and ref-based listening controls.
- SpeechToTextComponent integration
- Voice form input handlers
- Error and permission recovery patterns
By the numbers
- Targets Syncfusion SpeechToText version 33.1.44
- Documents 6 reference guides and 12 TooltipPosition placement values
Files
Syncfusion React SpeechToText Component
Component Overview
The SpeechToText component enables users to convert spoken words into text using the Web Speech API. This skill helps you implement, customize, and troubleshoot speech recognition in React applications. The main component that captures audio from the user's microphone and converts speech to text in real-time using browser APIs.
Key Capabilities
- Real-time speech recognition
- Multiple language support
- Customizable button and tooltip
- Event-driven architecture
- Programmatic control via methods
- Accessibility support (ARIA labels, keyboard navigation)
- Localization support
- Error handling and recovery
Documentation
Getting Started
📄 Read: references/getting-started.md
- Installation via npm
- Package installation and setup
- Basic component implementation
- CSS imports and theme selection
- First working example
- TypeScript configuration
- Disabling the component (
disabledproperty)
Speech Recognition Features
📄 Read: references/speech-recognition-features.md
- Retrieving transcripts in real-time
- Setting language for recognition
- Managing interim results
- Listening state management with
SpeechToTextStateenum (Inactive, Listening, Stopped) - Reading
listeningStatefrom event args and component ref - Handling speech-to-text conversion
- Real-time vs final results
Button and Tooltip Customization
📄 Read: references/button-and-tooltip-customization.md
- Customizing button content and icons
- Icon positioning and styling
- Controlling tooltip visibility (
showTooltipproperty) - Tooltip configuration and placement (all 12
TooltipPositionvalues) - CSS class styling (e-primary, e-success, etc.)
- Button appearance modes
- Responsive button design
Events and Methods
📄 Read: references/events-and-methods.md
- Event handling (created, onStart, onStop, onError, transcriptChanged)
- Correct event argument interfaces (StartListeningEventArgs, StopListeningEventArgs, ErrorEventArgs, TranscriptChangedEventArgs)
cancelproperty to prevent listening startisInteractedto distinguish user vs programmatic triggerserrorMessagefor human-readable error detailsisInterimResultfor interim vs final transcript results- startListening(), stopListening(), and destroy() methods
- Ref-based component control
- Programmatic listening management
Globalization and Localization
📄 Read: references/globalization-and-localization.md
- Localization with L10n.load()
- Available locale strings and translations
- Language-specific error messages
- RTL support for right-to-left languages
- Accessibility labels and ARIA attributes
htmlAttributesfor custom HTML/ARIA attributes on the button element- Multi-language interface support
Troubleshooting and Security
📄 Read: references/troubleshooting-and-security.md
- Common issues and solutions
- Browser compatibility matrix
- Microphone permission handling
- Security considerations and best practices
- Privacy and data transmission
- Performance optimization
- Offline fallback strategies
Quick Start Example
import { SpeechToTextComponent, TextAreaComponent, TranscriptChangedEventArgs } from '@syncfusion/ej2-react-inputs';
import { useState } from 'react';
import '@syncfusion/ej2-react-inputs/styles/material.css';
function VoiceNoteApp() {
const [transcript, setTranscript] = useState('');
const handleTranscriptChanged = (args: TranscriptChangedEventArgs) => {
setTranscript(args.transcript);
};
return (
<div style={{ padding: '20px' }}>
<h2>Voice Note Recorder</h2>
{/* SpeechToText component with microphone button */}
<SpeechToTextComponent
id="speechToText"
transcriptChanged={handleTranscriptChanged}
/>
{/* Display transcribed text */}
<TextAreaComponent
id="noteArea"
value={transcript}
resizeMode="None"
rows={5}
cols={50}
placeholder="Your voice will appear here..."
/>
</div>
);
}
export default VoiceNoteApp;Common Patterns
Pattern 1: Voice Form Input
import { SpeechToTextComponent, TextBoxComponent } from '@syncfusion/ej2-react-inputs';
import { useState } from 'react';
function VoiceForm() {
const [formData, setFormData] = useState({
name: '',
message: ''
});
const handleNameTranscript = (args: any) => {
setFormData(prev => ({ ...prev, name: args.transcript }));
};
const handleMessageTranscript = (args: any) => {
setFormData(prev => ({ ...prev, message: args.transcript }));
};
return (
<div>
<label>Name (speak):</label>
<SpeechToTextComponent transcriptChanged={handleNameTranscript} />
<TextBoxComponent value={formData.name} />
<label>Message (speak):</label>
<SpeechToTextComponent transcriptChanged={handleMessageTranscript} />
<TextBoxComponent value={formData.message} />
</div>
);
}Pattern 2: Programmatic Control
import { SpeechToTextComponent } from '@syncfusion/ej2-react-inputs';
import { useRef } from 'react';
function VoiceControlApp() {
const speechRef = useRef<SpeechToTextComponent>(null);
const startVoiceInput = () => {
speechRef.current?.startListening();
};
const stopVoiceInput = () => {
speechRef.current?.stopListening();
};
return (
<div>
<SpeechToTextComponent ref={speechRef} />
<button onClick={startVoiceInput}>Start Recording</button>
<button onClick={stopVoiceInput}>Stop Recording</button>
</div>
);
}Pattern 3: Error Handling
import { SpeechToTextComponent, ErrorEventArgs } from '@syncfusion/ej2-react-inputs';
import { useState } from 'react';
function VoiceWithErrorHandling() {
const [error, setError] = useState('');
const [isListening, setIsListening] = useState(false);
const handleError = (args: ErrorEventArgs) => {
// args.errorMessage is the human-readable description; args.error is the error code
setError(args.errorMessage || `Error: ${args.error}`);
};
const handleStart = () => {
setIsListening(true);
setError('');
};
const handleStop = () => {
setIsListening(false);
};
return (
<div>
<SpeechToTextComponent
onError={handleError}
onStart={handleStart}
onStop={handleStop}
/>
{isListening && <p>🎤 Listening...</p>}
{error && <p style={{ color: 'red' }}>{error}</p>}
</div>
);
}Key Props
| Prop | Type | Description |
|---|---|---|
lang | string | Language for speech recognition (e.g., 'en-US', 'fr-FR') |
transcript | string | Current transcribed text |
allowInterimResults | boolean | Show real-time results (default: true) |
listeningState | SpeechToTextState | Current listening state (Inactive, Listening, Stopped) |
buttonSettings | ButtonSettingsModel | Customize button appearance and content |
tooltipSettings | TooltipSettingsModel | Configure tooltip display |
showTooltip | boolean | Whether to display the tooltip on hover (default: true) |
cssClass | string | Apply CSS classes for styling |
disabled | boolean | Disable all component interaction (default: false) |
htmlAttributes | { [key: string]: string } | Additional HTML attributes (ARIA, data-*, etc.) for the root button element |
locale | string | Localization language code |
enableRtl | boolean | Enable right-to-left layout |
enablePersistence | boolean | Persist component state between page reloads via localStorage |
Event Handlers
| Event | Args | Description |
|---|---|---|
created | - | Fired when component is initialized |
onStart | StartListeningEventArgs | Fired when speech recognition begins. Args: cancel, event, isInteracted, listeningState, name |
onStop | StopListeningEventArgs | Fired when speech recognition ends. Args: event, isInteracted, listeningState, name |
onError | ErrorEventArgs | Fired when an error occurs. Args: error, errorMessage, event, name |
transcriptChanged | TranscriptChangedEventArgs | Fired when transcription updates. Args: transcript, isInterimResult, event, name |
Methods
| Method | Description |
|---|---|
startListening() | Begin speech recognition programmatically |
stopListening() | Stop speech recognition programmatically |
destroy() | Destroy the component instance and release all resources |
Troubleshooting
Microphone permission denied
Solution: Check browser permissions settings and allow microphone access in security settings
Speech not recognized
Solution: Check microphone volume, speak clearly, verify correct language setting
Component not rendering
Solution: Ensure CSS imports are included and license key is registered
Browser not supported
Solution: Check if browser supports Web Speech API (Chrome, Edge, Safari support it)
Related Components
- TextArea: For displaying transcribed text
- TextBox: For input fields with voice capabilities
- Button: For custom voice control buttons
- Tooltip: For contextual help on voice features
Button and Tooltip Customization
Table of Contents
- Customizing Button Content
- Icon Customization
- Icon Positioning
- Primary Button Styling
- Controlling Tooltip Visibility
- Tooltip Configuration
- CSS Class Styling
- Complete Customization Examples
Customizing Button Content
You can customize the text displayed on the button in both listening and stopped states using the buttonSettings property.
Setting Button Text
import { SpeechToTextComponent, ButtonSettingsModel } from '@syncfusion/ej2-react-inputs';
function ButtonTextDemo() {
const buttonSettings: ButtonSettingsModel = {
content: 'Start Listening', // Text when not listening
stopContent: 'Stop Listening' // Text when listening
};
return (
<SpeechToTextComponent
buttonSettings={buttonSettings}
/>
);
}
export default ButtonTextDemo;Minimal Button Text
import { SpeechToTextComponent, ButtonSettingsModel } from '@syncfusion/ej2-react-inputs';
function MinimalButtonDemo() {
const buttonSettings: ButtonSettingsModel = {
content: 'Start',
stopContent: 'Stop'
};
return (
<SpeechToTextComponent
buttonSettings={buttonSettings}
/>
);
}Icon Customization
Customize the appearance of button icons using CSS icon classes.
Available Icon Classes
Syncfusion provides icon classes from the e-icons font:
e-icons e-play- Play icone-icons e-pause- Pause icone-icons e-stop- Stop icone-icons e-mic- Microphone icone-icons e-speaker- Speaker icone-icons e-close- Close icon- Custom CSS class names for custom icons
Setting Icons
import { SpeechToTextComponent, ButtonSettingsModel } from '@syncfusion/ej2-react-inputs';
import '@syncfusion/ej2-icons/styles/material.css';
function IconDemo() {
const buttonSettings: ButtonSettingsModel = {
content: 'Record',
stopContent: 'Stop',
iconCss: 'e-icons e-play', // Icon when not listening
stopIconCss: 'e-icons e-pause' // Icon when listening
};
return (
<div>
<SpeechToTextComponent
buttonSettings={buttonSettings}
/>
</div>
);
}
export default IconDemo;Using Different Icons
import { SpeechToTextComponent, ButtonSettingsModel } from '@syncfusion/ej2-react-inputs';
function AlternateIconDemo() {
const buttonSettings: ButtonSettingsModel = {
iconCss: 'e-icons e-mic', // Microphone icon
stopIconCss: 'e-icons e-stop' // Stop icon
};
return (
<SpeechToTextComponent
buttonSettings={buttonSettings}
/>
);
}Custom Icons
Add custom CSS for your own icons:
import { SpeechToTextComponent, ButtonSettingsModel } from '@syncfusion/ej2-react-inputs';
function CustomIconDemo() {
const buttonSettings: ButtonSettingsModel = {
iconCss: 'custom-icon-start',
stopIconCss: 'custom-icon-stop'
};
const customStyles = `
.custom-icon-start::before {
content: '🎤';
margin-right: 8px;
}
.custom-icon-stop::before {
content: '⏹️';
margin-right: 8px;
}
`;
return (
<div>
<style>{customStyles}</style>
<SpeechToTextComponent
buttonSettings={buttonSettings}
/>
</div>
);
}
export default CustomIconDemo;Icon Positioning
Control where the icon appears relative to the button text.
Icon Position Options
Left- Icon on the left side of text (default)Right- Icon on the right side of textTop- Icon above the textBottom- Icon below the text
Positioning Examples
import { SpeechToTextComponent, ButtonSettingsModel } from '@syncfusion/ej2-react-inputs';
function IconPositionDemo() {
// Icon on the right
const rightPosition: ButtonSettingsModel = {
content: 'Start',
stopContent: 'Stop',
iconCss: 'e-icons e-play',
stopIconCss: 'e-icons e-pause',
iconPosition: 'Right'
};
// Icon on top
const topPosition: ButtonSettingsModel = {
content: 'Record',
iconCss: 'e-icons e-mic',
iconPosition: 'Top'
};
// Icon on bottom
const bottomPosition: ButtonSettingsModel = {
content: 'Listen',
iconCss: 'e-icons e-speaker',
iconPosition: 'Bottom'
};
return (
<div style={{ display: 'flex', gap: '20px' }}>
<div>
<p>Icon Right:</p>
<SpeechToTextComponent buttonSettings={rightPosition} />
</div>
<div>
<p>Icon Top:</p>
<SpeechToTextComponent buttonSettings={topPosition} />
</div>
<div>
<p>Icon Bottom:</p>
<SpeechToTextComponent buttonSettings={bottomPosition} />
</div>
</div>
);
}
export default IconPositionDemo;Primary Button Styling
The isPrimary property makes the button visually prominent with primary action styling.
Primary Button
import { SpeechToTextComponent, ButtonSettingsModel } from '@syncfusion/ej2-react-inputs';
function PrimaryButtonDemo() {
const buttonSettings: ButtonSettingsModel = {
content: 'Start Recording',
stopContent: 'Stop Recording',
isPrimary: true // Makes button prominent
};
return (
<SpeechToTextComponent
buttonSettings={buttonSettings}
/>
);
}
export default PrimaryButtonDemo;Combining with Other Customizations
import { SpeechToTextComponent, ButtonSettingsModel } from '@syncfusion/ej2-react-inputs';
function AdvancedButtonDemo() {
const buttonSettings: ButtonSettingsModel = {
content: 'Start',
stopContent: 'Stop',
iconCss: 'e-icons e-play',
stopIconCss: 'e-icons e-stop',
iconPosition: 'Right',
isPrimary: true
};
return (
<SpeechToTextComponent
buttonSettings={buttonSettings}
/>
);
}
export default AdvancedButtonDemo;Controlling Tooltip Visibility
The showTooltip property (default: true) controls whether the tooltip is displayed at all when hovering over the SpeechToText button. Set it to false to completely hide the tooltip.
import { SpeechToTextComponent } from '@syncfusion/ej2-react-inputs';
function NoTooltipDemo() {
return (
// Tooltip is hidden — no hover popup appears
<SpeechToTextComponent showTooltip={false} />
);
}
export default NoTooltipDemo;Conditionally Toggling Tooltip
import { SpeechToTextComponent } from '@syncfusion/ej2-react-inputs';
import { useState } from 'react';
function ToggleTooltipDemo() {
const [showTooltip, setShowTooltip] = useState(true);
return (
<div>
<label>
<input
type="checkbox"
checked={showTooltip}
onChange={e => setShowTooltip(e.target.checked)}
/>
Show Tooltip
</label>
<SpeechToTextComponent showTooltip={showTooltip} />
</div>
);
}
export default ToggleTooltipDemo;Tooltip Configuration
Customize the tooltip that appears when hovering over the button using tooltipSettings.
Basic Tooltip
import { SpeechToTextComponent, TooltipSettingsModel } from '@syncfusion/ej2-react-inputs';
function TooltipDemo() {
const tooltipSettings: TooltipSettingsModel = {
content: 'Click to start speech recognition',
stopContent: 'Click to stop recording'
};
return (
<SpeechToTextComponent
tooltipSettings={tooltipSettings}
/>
);
}
export default TooltipDemo;Tooltip Position
Control where the tooltip appears:
import { SpeechToTextComponent, TooltipSettingsModel } from '@syncfusion/ej2-react-inputs';
function TooltipPositionDemo() {
const tooltipSettings: TooltipSettingsModel = {
position: 'TopCenter', // TopCenter, TopLeft, TopRight
content: 'Click to record',
stopContent: 'Click to stop'
};
return (
<SpeechToTextComponent
tooltipSettings={tooltipSettings}
/>
);
}
export default TooltipPositionDemo;Tooltip Position Options
All valid TooltipPosition enum values:
| Value | Description |
|---|---|
TopLeft | Appears at the top-left corner of the button |
TopCenter | Appears at the top-center of the button |
TopRight | Appears at the top-right corner of the button |
BottomLeft | Appears at the bottom-left corner of the button |
BottomCenter | Appears at the bottom-center of the button |
BottomRight | Appears at the bottom-right corner of the button |
LeftTop | Appears at the left-top corner of the button |
LeftCenter | Appears at the left-center of the button |
LeftBottom | Appears at the left-bottom corner of the button |
RightTop | Appears at the right-top corner of the button |
RightCenter | Appears at the right-center of the button |
RightBottom | Appears at the right-bottom corner of the button |
CSS Class Styling
Apply predefined or custom CSS classes for styling.
Predefined CSS Classes
import { SpeechToTextComponent } from '@syncfusion/ej2-react-inputs';
function PredefinedStylesDemo() {
return (
<div style={{ display: 'flex', flexDirection: 'column', gap: '20px' }}>
{/* Primary button */}
<SpeechToTextComponent cssClass="e-primary" />
{/* Success button */}
<SpeechToTextComponent cssClass="e-success" />
{/* Info button */}
<SpeechToTextComponent cssClass="e-info" />
{/* Warning button */}
<SpeechToTextComponent cssClass="e-warning" />
{/* Danger button */}
<SpeechToTextComponent cssClass="e-danger" />
{/* Outline button */}
<SpeechToTextComponent cssClass="e-outline" />
</div>
);
}
export default PredefinedStylesDemo;Custom CSS Classes
import { SpeechToTextComponent } from '@syncfusion/ej2-react-inputs';
function CustomStyleDemo() {
const customStyles = `
.custom-voice-btn.e-btn {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border: none;
border-radius: 25px;
padding: 12px 30px;
font-weight: bold;
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
}
.custom-voice-btn.e-btn:hover {
box-shadow: 0 6px 20px rgba(0, 0, 0, 0.3);
}
`;
return (
<div>
<style>{customStyles}</style>
<SpeechToTextComponent cssClass="custom-voice-btn" />
</div>
);
}
export default CustomStyleDemo;Complete Customization Examples
Example 1: Modern Voice Button
import { SpeechToTextComponent, ButtonSettingsModel, TooltipSettingsModel } from '@syncfusion/ej2-react-inputs';
import { useState } from 'react';
function ModernVoiceButton() {
const [isListening, setIsListening] = useState(false);
const buttonSettings: ButtonSettingsModel = {
content: 'Start',
stopContent: 'Stop',
iconCss: 'e-icons e-play',
stopIconCss: 'e-icons e-stop',
iconPosition: 'Right',
isPrimary: true
};
const tooltipSettings: TooltipSettingsModel = {
position: 'TopCenter',
content: 'Click to start recording your voice',
stopContent: 'Click to stop recording'
};
return (
<div style={{ padding: '20px' }}>
<SpeechToTextComponent
buttonSettings={buttonSettings}
tooltipSettings={tooltipSettings}
cssClass="e-primary"
onStart={() => setIsListening(true)}
onStop={() => setIsListening(false)}
/>
{isListening && <p style={{ color: 'red' }}>🎤 Recording...</p>}
</div>
);
}
export default ModernVoiceButton;Example 2: Minimalist Design
import { SpeechToTextComponent, ButtonSettingsModel } from '@syncfusion/ej2-react-inputs';
function MinimalistDesign() {
const buttonSettings: ButtonSettingsModel = {
content: '', // No text
stopContent: '',
iconCss: 'e-icons e-mic',
stopIconCss: 'e-icons e-close',
isPrimary: false
};
const customStyles = `
.minimalist-btn.e-btn {
width: 50px;
height: 50px;
border-radius: 50%;
padding: 0;
display: flex;
align-items: center;
justify-content: center;
background-color: #f0f0f0;
border: 2px solid #ddd;
}
.minimalist-btn.e-btn:hover {
background-color: #e0e0e0;
}
`;
return (
<div>
<style>{customStyles}</style>
<SpeechToTextComponent
cssClass="minimalist-btn"
buttonSettings={buttonSettings}
/>
</div>
);
}
export default MinimalistDesign;Example 3: Accessible Voice Input
import { SpeechToTextComponent, ButtonSettingsModel, TooltipSettingsModel } from '@syncfusion/ej2-react-inputs';
function AccessibleVoiceInput() {
const buttonSettings: ButtonSettingsModel = {
content: 'Start Voice Input',
stopContent: 'Stop Voice Input',
iconCss: 'e-icons e-play',
stopIconCss: 'e-icons e-pause',
iconPosition: 'Left',
isPrimary: true
};
const tooltipSettings: TooltipSettingsModel = {
position: 'TopCenter',
content: 'Press enter or click to activate voice input. Speak clearly into your microphone.',
stopContent: 'Press enter or click to deactivate voice input.'
};
return (
<div style={{ padding: '20px', maxWidth: '400px' }}>
<label htmlFor="voiceInput" style={{ display: 'block', marginBottom: '10px', fontWeight: 'bold' }}>
Voice Input Control
</label>
<SpeechToTextComponent
id="voiceInput"
buttonSettings={buttonSettings}
tooltipSettings={tooltipSettings}
cssClass="e-primary"
/>
<p style={{ fontSize: '14px', color: '#666', marginTop: '10px' }}>
Use this button to provide voice input. Speak naturally and pause between sentences.
</p>
</div>
);
}
export default AccessibleVoiceInput;Troubleshooting
Icons not showing
- Ensure
@syncfusion/ej2-icons/styles/material.cssis imported - Verify icon class names are correct
Tooltip not appearing
- Check that
tooltipSettingsis properly configured - Ensure position property uses correct enum values
Custom CSS not applying
- Verify CSS class name matches in component and styles
- Check CSS specificity - Syncfusion classes might override your styles
- Use
!importantif needed, or increase specificity with more selectors
Events and Methods
Table of Contents
- Event Handlers
- Event Arguments
- Error Types
- Methods
- startListening()
- stopListening()
- destroy()
- Programmatic Control
- Event Workflows
- Error Handling
Event Handlers
The SpeechToText component provides five main events for handling different stages of speech recognition.
Available Events
| Event | Fires | Description |
|---|---|---|
created | After component initialization | Component is ready to use |
onStart | When listening begins | Speech recognition started |
onStop | When listening ends | Speech recognition stopped |
onError | When an error occurs | Error during recognition |
transcriptChanged | During recognition | Transcript text changes |
Basic Event Handling
import { SpeechToTextComponent } from '@syncfusion/ej2-react-inputs';
function EventHandlingDemo() {
const handleCreated = () => {
console.log('✓ Component initialized');
};
const handleStart = (args: any) => {
console.log('🎤 Started listening');
};
const handleStop = (args: any) => {
console.log('⏹️ Stopped listening');
};
const handleError = (args: any) => {
console.error('❌ Error:', args.error);
};
const handleTranscriptChanged = (args: any) => {
console.log('📝 Transcript:', args.transcript);
};
return (
<SpeechToTextComponent
created={handleCreated}
onStart={handleStart}
onStop={handleStop}
onError={handleError}
transcriptChanged={handleTranscriptChanged}
/>
);
}
export default EventHandlingDemo;Event Arguments
Each event provides specific data through its arguments object.
TranscriptChangedEventArgs
Contains transcript information during speech recognition:
| Property | Type | Description |
|---|---|---|
transcript | string | The transcribed text captured from the speech input. |
isInterimResult | boolean | true if the result is interim (still processing); false if it is the final result. Determined by the allowInterimResults property. |
event | Event | The native browser event associated with the transcript update. |
name | string | Name of the event ('transcriptChanged'). |
Usage:
import { SpeechToTextComponent, TranscriptChangedEventArgs } from '@syncfusion/ej2-react-inputs';
function TranscriptEventDemo() {
const handleTranscriptChanged = (args: TranscriptChangedEventArgs) => {
if (args.isInterimResult) {
console.log('[Interim] transcript:', args.transcript);
} else {
console.log('[Final] transcript:', args.transcript);
}
};
return (
<SpeechToTextComponent
transcriptChanged={handleTranscriptChanged}
/>
);
}StartListeningEventArgs
Contains information when listening starts:
| Property | Type | Description |
|---|---|---|
cancel | boolean | Set to true to prevent listening from starting. Useful for conditional validation before recognition begins. |
event | Event | The native browser event associated with the start listening action. |
isInteracted | boolean | true if triggered by user interaction (button click); false if triggered programmatically via startListening(). |
listeningState | SpeechToTextState | The current state of the component when listening starts. |
name | string | Name of the event ('onStart'). |
Usage:
import { SpeechToTextComponent, StartListeningEventArgs, SpeechToTextState } from '@syncfusion/ej2-react-inputs';
import { useState } from 'react';
function StartEventDemo() {
const [isListening, setIsListening] = useState(false);
const handleStart = (args: StartListeningEventArgs) => {
console.log('Triggered by user?', args.isInteracted);
console.log('Current state:', args.listeningState); // SpeechToTextState.Listening
setIsListening(true);
};
return (
<div>
<SpeechToTextComponent onStart={handleStart} />
{isListening && <p>🎤 Currently listening...</p>}
</div>
);
}Cancelling Listening on Start
Use cancel to conditionally prevent listening from starting:
import { SpeechToTextComponent, StartListeningEventArgs } from '@syncfusion/ej2-react-inputs';
function ConditionalListeningDemo() {
const [isFormValid, setIsFormValid] = useState(true);
const handleStart = (args: StartListeningEventArgs) => {
if (!isFormValid) {
args.cancel = true; // Prevent listening from starting
console.log('Listening cancelled: form is not valid.');
}
};
return (
<div>
<label>
<input type="checkbox" checked={isFormValid} onChange={e => setIsFormValid(e.target.checked)} />
Form is valid
</label>
<SpeechToTextComponent onStart={handleStart} />
</div>
);
}StopListeningEventArgs
Contains information when listening stops:
| Property | Type | Description |
|---|---|---|
event | Event | The native browser event associated with the stop listening action. |
isInteracted | boolean | true if triggered by user interaction (button click); false if triggered programmatically via stopListening(). |
listeningState | SpeechToTextState | The current state of the component when listening stops. |
name | string | Name of the event ('onStop'). |
Usage:
import { SpeechToTextComponent, StopListeningEventArgs, SpeechToTextState } from '@syncfusion/ej2-react-inputs';
function StopEventDemo() {
const handleStop = (args: StopListeningEventArgs) => {
console.log('Listening stopped');
console.log('Triggered by user?', args.isInteracted);
console.log('Current state:', args.listeningState); // SpeechToTextState.Stopped
};
return (
<SpeechToTextComponent onStop={handleStop} />
);
}ErrorEventArgs
Contains error information:
| Property | Type | Description |
|---|---|---|
error | string | Error code describing the type of error (e.g., 'audio-capture', 'not-allowed'). |
errorMessage | string | A human-readable message providing further details about the error for user-facing display or logging. |
event | Event | The native browser event data provided when the error is triggered. |
name | string | Name of the event ('onError'). |
Error Types
The component can report various error types through the onError event.
Common Error Types
| Error | Meaning | Solution |
|---|---|---|
no-speech | No speech detected | Speak louder/clearer |
audio-capture | Microphone unavailable | Check microphone connection |
network | Network error | Check internet connection |
not-allowed | Microphone permission denied | Allow microphone access |
service-not-allowed | Service blocked | Check browser settings |
bad-grammar | Grammar error | N/A (browser API) |
aborted | Recognition aborted | User or system interrupted |
Error Handling Pattern
import { SpeechToTextComponent, ErrorEventArgs } from '@syncfusion/ej2-react-inputs';
import { useState } from 'react';
function ErrorHandlingDemo() {
const [error, setError] = useState('');
const handleError = (args: ErrorEventArgs) => {
const errorMessages: { [key: string]: string } = {
'no-speech': '🔇 No speech detected. Please try again.',
'audio-capture': '🎙️ Microphone not found. Check your device.',
'network': '🌐 Network error. Check your connection.',
'not-allowed': '🔒 Microphone permission denied. Allow access in settings.',
'service-not-allowed': '⛔ Service not allowed in this context.',
'aborted': '⏹️ Speech recognition was interrupted.'
};
// args.errorMessage provides a human-readable description from the component
const message = errorMessages[args.error] || args.errorMessage || `Error: ${args.error}`;
setError(message);
// Auto-clear error after 5 seconds
setTimeout(() => setError(''), 5000);
};
return (
<div>
<SpeechToTextComponent onError={handleError} />
{error && (
<div style={{
padding: '10px',
marginTop: '10px',
backgroundColor: '#ffebee',
borderLeft: '4px solid #f44336',
color: '#c62828'
}}>
{error}
</div>
)}
</div>
);
}
export default ErrorHandlingDemo;Methods
The component provides two main methods for programmatic control.
startListening() Method
Programmatically start speech recognition without user clicking the button.
import { SpeechToTextComponent } from '@syncfusion/ej2-react-inputs';
import { useRef } from 'react';
function ProgrammaticStartDemo() {
const speechRef = useRef<SpeechToTextComponent>(null);
const startRecording = () => {
speechRef.current?.startListening();
};
return (
<div>
<SpeechToTextComponent ref={speechRef} />
<button onClick={startRecording} style={{ marginTop: '10px' }}>
Start Recording
</button>
</div>
);
}
export default ProgrammaticStartDemo;stopListening() Method
Programmatically stop speech recognition.
import { SpeechToTextComponent } from '@syncfusion/ej2-react-inputs';
import { useRef } from 'react';
function ProgrammaticStopDemo() {
const speechRef = useRef<SpeechToTextComponent>(null);
const stopRecording = () => {
speechRef.current?.stopListening();
};
return (
<div>
<SpeechToTextComponent ref={speechRef} />
<button onClick={stopRecording} style={{ marginTop: '10px' }}>
Stop Recording
</button>
</div>
);
}
export default ProgrammaticStopDemo;destroy() Method
Destroys the SpeechToText component instance and releases all associated resources. Call this during component unmount in dynamic UIs to prevent memory leaks.
import { SpeechToTextComponent } from '@syncfusion/ej2-react-inputs';
import { useRef, useEffect } from 'react';
function DestroyDemo() {
const speechRef = useRef<SpeechToTextComponent>(null);
useEffect(() => {
// Cleanup: destroy the component when the parent unmounts
return () => {
speechRef.current?.destroy();
};
}, []);
return (
<div>
<SpeechToTextComponent ref={speechRef} />
</div>
);
}
export default DestroyDemo;Note: After callingdestroy(), the component instance is no longer usable. Do not callstartListening()orstopListening()on a destroyed instance.
Programmatic Control
Full programmatic control over speech recognition:
import { SpeechToTextComponent, TextAreaComponent, TranscriptChangedEventArgs } from '@syncfusion/ej2-react-inputs';
import { useRef, useState } from 'react';
function FullControlDemo() {
const speechRef = useRef<SpeechToTextComponent>(null);
const [transcript, setTranscript] = useState('');
const [isListening, setIsListening] = useState(false);
const handleStart = () => {
setIsListening(true);
};
const handleStop = () => {
setIsListening(false);
};
const handleTranscript = (args: TranscriptChangedEventArgs) => {
setTranscript(args.transcript);
};
const toggleListening = () => {
if (isListening) {
speechRef.current?.stopListening();
} else {
speechRef.current?.startListening();
}
};
const clearTranscript = () => {
setTranscript('');
};
return (
<div style={{ padding: '20px' }}>
<div style={{ marginBottom: '20px' }}>
<SpeechToTextComponent
ref={speechRef}
onStart={handleStart}
onStop={handleStop}
transcriptChanged={handleTranscript}
/>
</div>
<div style={{ display: 'flex', gap: '10px', marginBottom: '20px' }}>
<button onClick={toggleListening} style={{ padding: '10px 20px' }}>
{isListening ? '⏹️ Stop' : '🎤 Start'}
</button>
<button onClick={clearTranscript} style={{ padding: '10px 20px' }}>
Clear
</button>
</div>
<TextAreaComponent
value={transcript}
rows={5}
placeholder="Transcript will appear here..."
/>
</div>
);
}
export default FullControlDemo;Event Workflows
Workflow 1: Simple Recording
const handleStart = () => console.log('Recording started');
const handleStop = () => console.log('Recording stopped');
const handleTranscript = (args: any) => console.log('Text:', args.transcript);
return (
<SpeechToTextComponent
onStart={handleStart}
onStop={handleStop}
transcriptChanged={handleTranscript}
/>
);Sequence: 1. User clicks button → onStart fires 2. User speaks → transcriptChanged fires repeatedly 3. User stops → onStop fires
Workflow 2: Form Submission with Voice
import { useState, useRef } from 'react';
function FormWithVoice() {
const [formData, setFormData] = useState({ name: '', email: '', message: '' });
const [isProcessing, setIsProcessing] = useState(false);
const handleFieldTranscript = (field: string, args: any) => {
setFormData(prev => ({ ...prev, [field]: args.transcript }));
};
const handleSubmit = async () => {
setIsProcessing(true);
try {
// Submit form
console.log('Submitting:', formData);
// await submitForm(formData);
} finally {
setIsProcessing(false);
}
};
return (
<div>
<SpeechToTextComponent
transcriptChanged={(args) => handleFieldTranscript('name', args)}
/>
<SpeechToTextComponent
transcriptChanged={(args) => handleFieldTranscript('email', args)}
/>
<SpeechToTextComponent
transcriptChanged={(args) => handleFieldTranscript('message', args)}
/>
<button onClick={handleSubmit} disabled={isProcessing}>
Submit
</button>
</div>
);
}Error Handling
Comprehensive Error Handling
import { SpeechToTextComponent, ErrorEventArgs } from '@syncfusion/ej2-react-inputs';
import { useState } from 'react';
function RobustErrorHandling() {
const [state, setState] = useState({
error: '',
isListening: false,
retryCount: 0,
maxRetries: 3
});
const handleError = (args: ErrorEventArgs) => {
setState(prev => ({
...prev,
error: args.errorMessage || args.error, // errorMessage is human-readable; error is the code
retryCount: prev.retryCount + 1
}));
};
const handleStart = () => {
setState(prev => ({
...prev,
error: '',
isListening: true,
retryCount: 0
}));
};
const handleStop = () => {
setState(prev => ({ ...prev, isListening: false }));
};
const canRetry = state.retryCount < state.maxRetries;
return (
<div style={{ padding: '20px' }}>
<SpeechToTextComponent
onStart={handleStart}
onStop={handleStop}
onError={handleError}
/>
{state.isListening && (
<p style={{ color: 'green' }}>🎤 Listening...</p>
)}
{state.error && (
<div style={{
padding: '10px',
marginTop: '10px',
backgroundColor: '#ffebee',
borderLeft: '4px solid #f44336',
color: '#c62828'
}}>
<p>Error: {state.error}</p>
<p>Attempt {state.retryCount} of {state.maxRetries}</p>
{canRetry && <p>Retrying...</p>}
{!canRetry && <p>Max retries exceeded. Please try again later.</p>}
</div>
)}
</div>
);
}
export default RobustErrorHandling;Troubleshooting
Method not found error
- Ensure ref is properly created with
useRef<SpeechToTextComponent>(null) - Check that component is rendered before calling methods
Events not firing
- Verify event handlers are properly bound
- Check browser console for errors
Microphone permission issues
- Handle
not-allowederror gracefully - Provide clear instructions to user
Getting Started with React SpeechToText Component
Installation
The SpeechToText component requires the Syncfusion React inputs package. Install it using npm:
npm install @syncfusion/ej2-react-inputs --saveProject Setup
Using Vite (Recommended)
Vite provides faster development and optimized builds for React applications.
npm create vite@latest my-app -- --template react-ts
cd my-app
npm run devInstall the Syncfusion package:
npm install @syncfusion/ej2-react-inputs --saveTypeScript Configuration
For TypeScript projects, ensure your tsconfig.json includes:
{
"compilerOptions": {
"target": "ES2020",
"jsx": "react-jsx",
"skipLibCheck": true,
"esModuleInterop": true
}
}Basic Implementation
Minimal Example (Functional Component)
import { SpeechToTextComponent } from '@syncfusion/ej2-react-inputs';
import '@syncfusion/ej2-react-inputs/styles/material.css';
function App() {
return (
<div>
<h1>Speech to Text</h1>
<SpeechToTextComponent id="speechToText" />
</div>
);
}
export default App;Minimal Example (Class Component)
import { SpeechToTextComponent } from '@syncfusion/ej2-react-inputs';
import { Component } from 'react';
import '@syncfusion/ej2-react-inputs/styles/material.css';
export default class App extends Component {
public render() {
return (
<div>
<h1>Speech to Text</h1>
<SpeechToTextComponent id="speechToText" />
</div>
);
}
}CSS Imports and Theme Selection
Available Themes
Syncfusion provides multiple built-in themes:
- Material (default)
- Bootstrap
- Fluent
- Fabric
- Tailwind
- Bootstrap 5
Importing CSS
// Material theme (default)
import '@syncfusion/ej2-react-inputs/styles/material.css';
// Bootstrap theme
import '@syncfusion/ej2-react-inputs/styles/bootstrap.css';
// Fluent theme
import '@syncfusion/ej2-react-inputs/styles/fluent.css';
// Include icon font CSS for button icons
import '@syncfusion/ej2-icons/styles/material.css';Using Multiple Themes
If you need icon support or additional styling:
import '@syncfusion/ej2-base/styles/material.css';
import '@syncfusion/ej2-buttons/styles/material.css';
import '@syncfusion/ej2-popups/styles/material.css';
import '@syncfusion/ej2-react-inputs/styles/material.css';
import '@syncfusion/ej2-icons/styles/material.css';First Working Example
Here's a complete example with text display:
import { SpeechToTextComponent, TextAreaComponent, TranscriptChangedEventArgs } from '@syncfusion/ej2-react-inputs';
import { useState } from 'react';
import '@syncfusion/ej2-react-inputs/styles/material.css';
function VoiceApp() {
const [transcript, setTranscript] = useState('');
const handleTranscriptChanged = (args: TranscriptChangedEventArgs) => {
setTranscript(args.transcript);
};
return (
<div style={{ padding: '20px', fontFamily: 'Arial' }}>
<h2>Speech to Text Demo</h2>
{/* Speech to Text Component */}
<div style={{ marginBottom: '20px' }}>
<p>Click the microphone button to start speaking:</p>
<SpeechToTextComponent
id="speechToText"
transcriptChanged={handleTranscriptChanged}
/>
</div>
{/* Display transcribed text */}
<div>
<p>Transcribed Text:</p>
<TextAreaComponent
id="transcriptArea"
value={transcript}
readOnly={false}
rows={5}
cols={50}
placeholder="Your speech will appear here..."
/>
</div>
</div>
);
}
export default VoiceApp;Disabling the Component
Use the disabled property to prevent all user interaction with the component. When true, clicking the microphone button has no effect and startListening() / stopListening() calls are ignored.
import { SpeechToTextComponent } from '@syncfusion/ej2-react-inputs';
import { useState } from 'react';
function DisabledDemo() {
const [isProcessing, setIsProcessing] = useState(false);
const handleSubmit = async () => {
setIsProcessing(true);
// Simulate async operation
await new Promise(resolve => setTimeout(resolve, 2000));
setIsProcessing(false);
};
return (
<div>
{/* Disable voice input while form is being submitted */}
<SpeechToTextComponent disabled={isProcessing} />
<button onClick={handleSubmit} disabled={isProcessing}>
{isProcessing ? 'Submitting...' : 'Submit'}
</button>
</div>
);
}
export default DisabledDemo;Note: Thedisabledproperty defaults tofalse. It is useful for preventing user interaction during loading states, form submission, or when the feature should be temporarily unavailable.
Handling Events
The component supports multiple events that fire during the speech recognition process:
import { SpeechToTextComponent, TranscriptChangedEventArgs } from '@syncfusion/ej2-react-inputs';
function EventDemo() {
const handleCreated = () => {
console.log('Component initialized');
};
const handleStart = (args: any) => {
console.log('Speech recognition started');
};
const handleStop = (args: any) => {
console.log('Speech recognition stopped');
};
const handleError = (args: any) => {
console.error('Error:', args.error);
};
const handleTranscriptChanged = (args: TranscriptChangedEventArgs) => {
console.log('Transcript:', args.transcript);
};
return (
<SpeechToTextComponent
created={handleCreated}
onStart={handleStart}
onStop={handleStop}
onError={handleError}
transcriptChanged={handleTranscriptChanged}
/>
);
}
export default EventDemo;License Registration
For production use, register your Syncfusion license key in your main App component:
import { registerLicense } from '@syncfusion/ej2-base';
// Register your license key
registerLicense('YOUR_LICENSE_KEY_HERE');
function App() {
return <SpeechToTextComponent id="speechToText" />;
}
export default App;Development Server
Start the development server:
Vite:
npm run devCreate React App:
npm startThe application will be available at http://localhost:5173 (Vite) or http://localhost:3000 (CRA).
Verification
Once the app is running, you should see: 1. A microphone button displayed on the page 2. The ability to click the button to start speaking 3. Text appearing as you speak (or after you finish, depending on settings)
If the microphone button doesn't appear, check:
- CSS imports are included
- Browser supports Web Speech API
- Microphone permissions are granted
Globalization and Localization
Table of Contents
- Localization Basics
- Available Locale Strings
- Implementing Localization
- Language Switching
- RTL Support
- Accessibility Labels
- Custom HTML Attributes
- Multi-Language Examples
Localization Basics
The SpeechToText component supports localization through the L10n.load() method, which allows you to translate component strings for different languages and cultures.
Default Locale
The component uses en-US (English - United States) by default.
import { SpeechToTextComponent } from '@syncfusion/ej2-react-inputs';
function DefaultLocaleDemo() {
return (
<SpeechToTextComponent
id="speechToText"
// Default locale is en-US
/>
);
}Setting Component Locale
Use the locale property to set a specific locale:
import { SpeechToTextComponent } from '@syncfusion/ej2-react-inputs';
function CustomLocaleDemo() {
return (
<div>
{/* German locale */}
<SpeechToTextComponent locale="de" />
{/* French locale */}
<SpeechToTextComponent locale="fr" />
{/* Spanish locale */}
<SpeechToTextComponent locale="es" />
</div>
);
}Available Locale Strings
The following strings can be localized:
| Key | English Default | Purpose |
|---|---|---|
abortedError | "Speech recognition was aborted." | Shown when recognition is aborted |
audioCaptureError | "No microphone detected. Ensure your microphone is connected." | Microphone not found |
defaultError | "An unknown error occurred." | Generic error message |
networkError | "Network error occurred. Check your internet connection." | Network connectivity issue |
noSpeechError | "No speech detected. Please speak into the microphone." | User didn't speak |
notAllowedError | "Microphone access denied. Allow microphone permissions." | Permission denied |
serviceNotAllowedError | "Speech recognition service is not allowed in this context." | Service blocked |
unsupportedBrowserError | "The browser does not support the SpeechRecognition API." | Browser not supported |
startAriaLabel | "Press to start speaking and transcribe your words" | Accessibility label for start |
stopAriaLabel | "Press to stop speaking and end transcription" | Accessibility label for stop |
startTooltipText | "Start listening" | Tooltip when not listening |
stopTooltipText | "Stop listening" | Tooltip when listening |
Implementing Localization
Basic Localization
import { SpeechToTextComponent } from '@syncfusion/ej2-react-inputs';
import { L10n } from '@syncfusion/ej2-base';
function LocalizationDemo() {
// Load German translations
L10n.load({
'de': {
'speech-to-text': {
'startTooltipText': 'Zum Starten klicken',
'stopTooltipText': 'Zum Stoppen klicken',
'noSpeechError': 'Keine Sprache erkannt. Bitte sprechen Sie in das Mikrofon.'
}
}
});
return (
<SpeechToTextComponent locale="de" />
);
}
export default LocalizationDemo;Complete Language Translation
import { SpeechToTextComponent } from '@syncfusion/ej2-react-inputs';
import { L10n } from '@syncfusion/ej2-base';
function FullGermanTranslation() {
L10n.load({
'de': {
'speech-to-text': {
'abortedError': 'Die Spracherkennung wurde abgebrochen.',
'audioCaptureError': 'Kein Mikrofon erkannt. Stellen Sie sicher, dass Ihr Mikrofon angeschlossen ist.',
'defaultError': 'Ein unbekannter Fehler ist aufgetreten.',
'networkError': 'Netzwerkfehler aufgetreten. Überprüfen Sie Ihre Internetverbindung.',
'noSpeechError': 'Keine Sprache erkannt. Bitte sprechen Sie in das Mikrofon.',
'notAllowedError': 'Mikrofonzugriff verweigert. Erlauben Sie Mikrofonberechtigungen.',
'serviceNotAllowedError': 'Der Spracherkennungsdienst ist in diesem Kontext nicht erlaubt.',
'unsupportedBrowserError': 'Der Browser unterstützt die SpeechRecognition API nicht.',
'startAriaLabel': 'Drücken Sie, um zu sprechen und Ihre Worte zu transkribieren',
'stopAriaLabel': 'Drücken Sie, um das Sprechen zu beenden und die Transkription zu stoppen',
'startTooltipText': 'Zuhören starten',
'stopTooltipText': 'Zuhören beenden'
}
}
});
return (
<SpeechToTextComponent locale="de" />
);
}
export default FullGermanTranslation;Language Switching
Implement dynamic language switching:
import { SpeechToTextComponent } from '@syncfusion/ej2-react-inputs';
import { L10n } from '@syncfusion/ej2-base';
import { useState } from 'react';
function LanguageSwitcher() {
const [selectedLanguage, setSelectedLanguage] = useState('en');
// Load translations for all supported languages
L10n.load({
'de': {
'speech-to-text': {
'startTooltipText': 'Zuhören starten',
'stopTooltipText': 'Zuhören beenden',
'noSpeechError': 'Keine Sprache erkannt.'
}
},
'fr': {
'speech-to-text': {
'startTooltipText': 'Commencer à écouter',
'stopTooltipText': 'Arrêter d\'écouter',
'noSpeechError': 'Aucune parole détectée.'
}
},
'es': {
'speech-to-text': {
'startTooltipText': 'Comenzar a escuchar',
'stopTooltipText': 'Dejar de escuchar',
'noSpeechError': 'No se detectó voz.'
}
}
});
return (
<div style={{ padding: '20px' }}>
<div style={{ marginBottom: '20px' }}>
<label>Select Language: </label>
<select
value={selectedLanguage}
onChange={(e) => setSelectedLanguage(e.target.value)}
>
<option value="en">English</option>
<option value="de">Deutsch</option>
<option value="fr">Français</option>
<option value="es">Español</option>
</select>
</div>
<SpeechToTextComponent
locale={selectedLanguage}
key={selectedLanguage} // Force re-render on language change
/>
</div>
);
}
export default LanguageSwitcher;RTL Support
Enable Right-to-Left (RTL) layout for languages like Arabic, Hebrew, and Persian.
Enabling RTL
import { SpeechToTextComponent } from '@syncfusion/ej2-react-inputs';
function RTLDemo() {
return (
<SpeechToTextComponent
enableRtl={true}
locale="ar" // Arabic locale
/>
);
}
export default RTLDemo;RTL with Arabic Translations
import { SpeechToTextComponent } from '@syncfusion/ej2-react-inputs';
import { L10n } from '@syncfusion/ej2-base';
function ArabicRTL() {
L10n.load({
'ar': {
'speech-to-text': {
'startTooltipText': 'اضغط للبدء في التحدث',
'stopTooltipText': 'اضغط للتوقف عن التحدث',
'noSpeechError': 'لم يتم الكشف عن كلام. يرجى التحدث في الميكروفون.',
'audioCaptureError': 'لم يتم الكشف عن ميكروفون.',
'notAllowedError': 'تم رفض الوصول إلى الميكروفون.'
}
}
});
return (
<div dir="rtl" style={{ padding: '20px' }}>
<SpeechToTextComponent
enableRtl={true}
locale="ar"
/>
</div>
);
}
export default ArabicRTL;RTL with Hebrew
import { SpeechToTextComponent } from '@syncfusion/ej2-react-inputs';
import { L10n } from '@syncfusion/ej2-base';
function HebrewRTL() {
L10n.load({
'he': {
'speech-to-text': {
'startTooltipText': 'לחץ כדי להתחיל לדבר',
'stopTooltipText': 'לחץ כדי להפסיק לדבר',
'noSpeechError': 'לא זוהה דיבור. אנא דברו למיקרופון.'
}
}
});
return (
<div dir="rtl">
<SpeechToTextComponent
enableRtl={true}
locale="he"
/>
</div>
);
}
export default HebrewRTL;Accessibility Labels
Use ARIA labels for screen reader support via L10n locale strings:
import { SpeechToTextComponent } from '@syncfusion/ej2-react-inputs';
import { L10n } from '@syncfusion/ej2-base';
function AccessibleLocalization() {
L10n.load({
'en': {
'speech-to-text': {
'startAriaLabel': 'Activate voice input. Press to start recording your message.',
'stopAriaLabel': 'Deactivate voice input. Press to stop recording your message.',
'startTooltipText': 'Click to start voice input',
'stopTooltipText': 'Click to stop voice input'
}
}
});
return (
<SpeechToTextComponent locale="en" />
);
}
export default AccessibleLocalization;Custom HTML Attributes
Use htmlAttributes to add arbitrary HTML attributes (ARIA attributes, data attributes, test IDs, etc.) directly to the root button element of the SpeechToText component.
import { SpeechToTextComponent } from '@syncfusion/ej2-react-inputs';
function HtmlAttributesDemo() {
return (
<SpeechToTextComponent
htmlAttributes={{
'aria-label': 'Start voice input for the name field',
'aria-describedby': 'voice-hint',
'data-testid': 'voice-btn-name',
'role': 'button'
}}
/>
);
}
export default HtmlAttributesDemo;Using htmlAttributes for Accessibility in Forms
import { SpeechToTextComponent } from '@syncfusion/ej2-react-inputs';
function AccessibleVoiceForm() {
return (
<form>
<div>
<label id="name-label" htmlFor="name-voice">Full Name (voice input)</label>
<SpeechToTextComponent
id="name-voice"
htmlAttributes={{
'aria-labelledby': 'name-label',
'aria-required': 'true',
'data-field': 'fullName'
}}
/>
<span id="voice-hint" style={{ fontSize: '12px', color: '#666' }}>
Click the microphone and speak your full name.
</span>
</div>
</form>
);
}
export default AccessibleVoiceForm;Multi-Language Examples
Example 1: Global Application
import { SpeechToTextComponent, TextAreaComponent } from '@syncfusion/ej2-react-inputs';
import { L10n } from '@syncfusion/ej2-base';
import { useState } from 'react';
function GlobalApp() {
const [language, setLanguage] = useState('en');
const [transcript, setTranscript] = useState('');
// Load all supported languages
L10n.load({
'en': {
'speech-to-text': {
'startTooltipText': 'Start listening',
'stopTooltipText': 'Stop listening',
'noSpeechError': 'No speech detected. Please speak into the microphone.'
}
},
'de': {
'speech-to-text': {
'startTooltipText': 'Zuhören starten',
'stopTooltipText': 'Zuhören beenden',
'noSpeechError': 'Keine Sprache erkannt. Bitte sprechen Sie in das Mikrofon.'
}
},
'fr': {
'speech-to-text': {
'startTooltipText': 'Commencer à écouter',
'stopTooltipText': 'Arrêter d\'écouter',
'noSpeechError': 'Aucune parole détectée. Veuillez parler au microphone.'
}
},
'es': {
'speech-to-text': {
'startTooltipText': 'Comenzar a escuchar',
'stopTooltipText': 'Dejar de escuchar',
'noSpeechError': 'No se detectó voz. Por favor, hable en el micrófono.'
}
},
'ja': {
'speech-to-text': {
'startTooltipText': 'リッスニングを開始',
'stopTooltipText': 'リッスニングを停止',
'noSpeechError': '音声が検出されていません。マイクに向かって話してください。'
}
}
});
const languages = {
en: 'English',
de: 'Deutsch',
fr: 'Français',
es: 'Español',
ja: '日本語'
};
return (
<div style={{ maxWidth: '600px', margin: '0 auto', padding: '20px' }}>
<h2>Multi-Language Voice Input</h2>
<div style={{ marginBottom: '20px' }}>
<label>Language: </label>
<select
value={language}
onChange={(e) => setLanguage(e.target.value)}
>
{Object.entries(languages).map(([code, name]) => (
<option key={code} value={code}>{name}</option>
))}
</select>
</div>
<SpeechToTextComponent
locale={language}
lang={language === 'ja' ? 'ja-JP' : language}
transcriptChanged={(args: any) => setTranscript(args.transcript)}
key={language}
/>
<div style={{ marginTop: '20px' }}>
<p>Transcript:</p>
<TextAreaComponent
value={transcript}
rows={5}
placeholder="Your speech will appear here..."
/>
</div>
</div>
);
}
export default GlobalApp;Example 2: Region-Specific App
import { SpeechToTextComponent } from '@syncfusion/ej2-react-inputs';
import { L10n } from '@syncfusion/ej2-base';
function RegionalApp() {
const userRegion = 'de'; // Could come from user settings
L10n.load({
'de': {
'speech-to-text': {
'startTooltipText': 'Zum Starten klicken',
'stopTooltipText': 'Zum Stoppen klicken',
'noSpeechError': 'Keine Sprache erkannt.'
}
}
});
return (
<div>
<h1>German Voice Input</h1>
<SpeechToTextComponent
locale={userRegion}
lang={`${userRegion}-DE`}
enableRtl={false}
/>
</div>
);
}
export default RegionalApp;Example 3: Bilingual Interface
import { SpeechToTextComponent } from '@syncfusion/ej2-react-inputs';
import { L10n } from '@syncfusion/ej2-base';
import { useState } from 'react';
function BilingualApp() {
const [activeLanguage, setActiveLanguage] = useState('en');
L10n.load({
'en': {
'speech-to-text': {
'startTooltipText': 'Click to start',
'stopTooltipText': 'Click to stop'
}
},
'es': {
'speech-to-text': {
'startTooltipText': 'Haga clic para comenzar',
'stopTooltipText': 'Haga clic para detener'
}
}
});
return (
<div style={{ display: 'flex', gap: '40px', padding: '20px' }}>
<div>
<h3>English</h3>
<SpeechToTextComponent
locale="en"
lang="en-US"
/>
</div>
<div>
<h3>Español</h3>
<SpeechToTextComponent
locale="es"
lang="es-ES"
/>
</div>
</div>
);
}
export default BilingualApp;Troubleshooting
Translations not appearing
- Ensure
L10n.load()is called before component renders - Check locale code matches (e.g., 'de' not 'de-DE' for L10n)
- Verify key names match exactly
RTL not working
- Set
enableRtl={true}on component - Wrap in
<div dir="rtl">for proper layout - Load RTL-appropriate translations
Language switching not updating
- Use
keyprop to force component re-render:key={language} - Ensure locale property updates when language changes
Speech Recognition Features
Table of Contents
- Retrieving Transcripts
- Setting Language
- Allowing Interim Results
- Managing Listening State
- Real-Time Speech Processing
- Multi-Language Support
Retrieving Transcripts
The transcript property allows you to access the text generated from spoken input. You can retrieve and display the transcribed text in your application.
Basic Transcript Retrieval
import { SpeechToTextComponent, TextAreaComponent, TranscriptChangedEventArgs } from '@syncfusion/ej2-react-inputs';
import { useState } from 'react';
function TranscriptDemo() {
const [transcript, setTranscript] = useState('');
const handleTranscriptChanged = (args: TranscriptChangedEventArgs) => {
// Update state with the latest transcript
setTranscript(args.transcript);
};
return (
<div>
<SpeechToTextComponent
transcriptChanged={handleTranscriptChanged}
/>
<TextAreaComponent
value={transcript}
placeholder="Transcribed text appears here..."
rows={5}
/>
</div>
);
}
export default TranscriptDemo;Accessing Transcript from Component Ref
import { SpeechToTextComponent } from '@syncfusion/ej2-react-inputs';
import { useRef } from 'react';
function DirectTranscriptAccess() {
const speechRef = useRef<SpeechToTextComponent>(null);
const getTranscript = () => {
const currentTranscript = speechRef.current?.transcript;
console.log('Current transcript:', currentTranscript);
};
return (
<div>
<SpeechToTextComponent ref={speechRef} />
<button onClick={getTranscript}>Get Transcript</button>
</div>
);
}Pre-filling Transcript
You can initialize the component with existing transcript text:
import { SpeechToTextComponent } from '@syncfusion/ej2-react-inputs';
function PreFilledTranscript() {
const initialText = 'Hello, this is a pre-filled transcript.';
return (
<div>
<SpeechToTextComponent
transcript={initialText}
/>
</div>
);
}Setting Language
The lang property specifies the language for speech recognition. This determines how the speech engine interprets spoken words.
Supported Languages
Common language codes:
en-US- English (US)en-GB- English (UK)fr-FR- Frenchde-DE- Germanes-ES- Spanishit-IT- Italianja-JP- Japanesezh-CN- Chinese (Simplified)zh-TW- Chinese (Traditional)pt-BR- Portuguese (Brazil)ru-RU- Russian
Setting a Specific Language
import { SpeechToTextComponent, TextAreaComponent } from '@syncfusion/ej2-react-inputs';
import { useState } from 'react';
function LanguageDemo() {
const [transcript, setTranscript] = useState('');
return (
<div>
<h3>French Speech Recognition</h3>
<SpeechToTextComponent
lang="fr-FR"
transcriptChanged={(args: any) => setTranscript(args.transcript)}
/>
<TextAreaComponent
value={transcript}
placeholder="Parlez en français..."
/>
</div>
);
}
export default LanguageDemo;Language Selection Dropdown
import { SpeechToTextComponent, TextAreaComponent, DropDownListComponent } from '@syncfusion/ej2-react-inputs';
import { useState } from 'react';
function LanguageSelector() {
const [language, setLanguage] = useState('en-US');
const [transcript, setTranscript] = useState('');
const languages = [
{ text: 'English (US)', value: 'en-US' },
{ text: 'English (UK)', value: 'en-GB' },
{ text: 'French', value: 'fr-FR' },
{ text: 'Spanish', value: 'es-ES' },
{ text: 'German', value: 'de-DE' },
{ text: 'Japanese', value: 'ja-JP' }
];
return (
<div>
<div>
<label>Select Language:</label>
<DropDownListComponent
dataSource={languages}
fields={{ text: 'text', value: 'value' }}
value={language}
change={(e: any) => setLanguage(e.value)}
/>
</div>
<SpeechToTextComponent
lang={language}
transcriptChanged={(args: any) => setTranscript(args.transcript)}
/>
<TextAreaComponent
value={transcript}
placeholder="Your speech will appear here..."
/>
</div>
);
}
export default LanguageSelector;Allowing Interim Results
The allowInterimResults property controls whether the component displays results in real-time as the user speaks or waits for the final result.
What are Interim Results?
- Interim Results (true): Text updates continuously while speaking (default)
- Final Results (false): Text updates only after speech recognition completes
Real-Time Results (Default)
import { SpeechToTextComponent, TextAreaComponent } from '@syncfusion/ej2-react-inputs';
import { useState } from 'react';
function RealTimeDemo() {
const [transcript, setTranscript] = useState('');
return (
<div>
<h3>Real-Time Transcription</h3>
<p>Text updates as you speak:</p>
<SpeechToTextComponent
allowInterimResults={true} // Default
transcriptChanged={(args: any) => setTranscript(args.transcript)}
/>
<TextAreaComponent
value={transcript}
rows={5}
placeholder="Real-time transcript..."
/>
</div>
);
}
export default RealTimeDemo;Final Results Only
import { SpeechToTextComponent, TextAreaComponent } from '@syncfusion/ej2-react-inputs';
import { useState } from 'react';
function FinalResultsDemo() {
const [transcript, setTranscript] = useState('');
return (
<div>
<h3>Final Results Only</h3>
<p>Text updates after you stop speaking:</p>
<SpeechToTextComponent
allowInterimResults={false}
transcriptChanged={(args: any) => setTranscript(args.transcript)}
/>
<TextAreaComponent
value={transcript}
rows={5}
placeholder="Final transcript will appear here..."
/>
</div>
);
}
export default FinalResultsDemo;Managing Listening State
The listeningState property indicates the current status of the component. It helps you understand whether the component is waiting for input, actively listening, or has stopped. Import the SpeechToTextState enum to work with state values in a type-safe way.
SpeechToTextState Enum
| Enum Value | String | Description |
|---|---|---|
SpeechToTextState.Inactive | 'Inactive' | Component is idle, not listening |
SpeechToTextState.Listening | 'Listening' | Component is actively capturing audio |
SpeechToTextState.Stopped | 'Stopped' | Speech recognition has ended |
Reading listeningState via Event Args
The listeningState is provided in StartListeningEventArgs and StopListeningEventArgs so you can read the exact state at the time each event fires:
import { SpeechToTextComponent, StartListeningEventArgs, StopListeningEventArgs, SpeechToTextState } from '@syncfusion/ej2-react-inputs';
import { useState } from 'react';
function ListeningStateDemo() {
const [currentState, setCurrentState] = useState<SpeechToTextState>(SpeechToTextState.Inactive);
const handleStart = (args: StartListeningEventArgs) => {
setCurrentState(args.listeningState); // SpeechToTextState.Listening
};
const handleStop = (args: StopListeningEventArgs) => {
setCurrentState(args.listeningState); // SpeechToTextState.Stopped
};
const stateLabels: Record<SpeechToTextState, string> = {
[SpeechToTextState.Inactive]: '⏸️ Inactive',
[SpeechToTextState.Listening]: '🎤 Listening',
[SpeechToTextState.Stopped]: '⏹️ Stopped',
};
return (
<div>
<div style={{
padding: '10px',
margin: '10px 0',
backgroundColor: currentState === SpeechToTextState.Listening ? '#ffeb3b' : '#e8f5e9',
borderRadius: '4px'
}}>
Status: {stateLabels[currentState]}
</div>
<SpeechToTextComponent
onStart={handleStart}
onStop={handleStop}
/>
</div>
);
}
export default ListeningStateDemo;Reading listeningState from a Ref
You can also read the current listeningState directly from the component ref at any time:
import { SpeechToTextComponent, SpeechToTextState } from '@syncfusion/ej2-react-inputs';
import { useRef } from 'react';
function ReadStateFromRef() {
const speechRef = useRef<SpeechToTextComponent>(null);
const checkState = () => {
const state = speechRef.current?.listeningState;
if (state === SpeechToTextState.Listening) {
console.log('Currently listening — stopping now.');
speechRef.current?.stopListening();
} else if (state === SpeechToTextState.Inactive) {
console.log('Idle — starting now.');
speechRef.current?.startListening();
}
};
return (
<div>
<SpeechToTextComponent ref={speechRef} />
<button onClick={checkState}>Toggle Listening</button>
</div>
);
}
export default ReadStateFromRef;Real-Time Speech Processing
Process transcribed text in real-time as the user speaks:
import { SpeechToTextComponent, TranscriptChangedEventArgs } from '@syncfusion/ej2-react-inputs';
import { useState } from 'react';
function RealtimeProcessing() {
const [transcript, setTranscript] = useState('');
const [wordCount, setWordCount] = useState(0);
const [letterCount, setLetterCount] = useState(0);
const handleTranscriptChanged = (args: TranscriptChangedEventArgs) => {
const text = args.transcript;
setTranscript(text);
// Count words
const words = text.trim().split(/\s+/).filter(w => w.length > 0);
setWordCount(words.length);
// Count letters
setLetterCount(text.replace(/\s/g, '').length);
};
return (
<div style={{ padding: '20px' }}>
<SpeechToTextComponent
transcriptChanged={handleTranscriptChanged}
/>
<div style={{ marginTop: '20px' }}>
<p>Transcript: {transcript}</p>
<p>Words: {wordCount}</p>
<p>Letters: {letterCount}</p>
</div>
</div>
);
}
export default RealtimeProcessing;Multi-Language Support
Implement a multi-language voice interface:
import { SpeechToTextComponent, TextAreaComponent } from '@syncfusion/ej2-react-inputs';
import { useState } from 'react';
function MultiLanguageVoiceApp() {
const [language, setLanguage] = useState('en-US');
const [transcript, setTranscript] = useState('');
const [isListening, setIsListening] = useState(false);
const languages = {
'en-US': 'English (US)',
'fr-FR': 'French',
'es-ES': 'Spanish',
'de-DE': 'German',
'ja-JP': 'Japanese'
};
const handleStart = () => {
setIsListening(true);
};
const handleStop = () => {
setIsListening(false);
};
return (
<div style={{ maxWidth: '600px', margin: '0 auto', padding: '20px' }}>
<h2>Multi-Language Voice Input</h2>
<div style={{ marginBottom: '20px' }}>
<label>Select Language: </label>
<select
value={language}
onChange={(e) => setLanguage(e.target.value)}
style={{ padding: '8px', fontSize: '16px' }}
>
{Object.entries(languages).map(([code, name]) => (
<option key={code} value={code}>{name}</option>
))}
</select>
</div>
<div style={{ marginBottom: '20px' }}>
<p>{isListening ? '🎤 Listening...' : 'Click to start speaking'}</p>
<SpeechToTextComponent
lang={language}
onStart={handleStart}
onStop={handleStop}
transcriptChanged={(args: any) => setTranscript(args.transcript)}
/>
</div>
<div>
<p>Transcribed Text:</p>
<TextAreaComponent
value={transcript}
readOnly={false}
rows={5}
placeholder="Your speech appears here..."
/>
</div>
</div>
);
}
export default MultiLanguageVoiceApp;Common Patterns
Pattern: Clear Transcript Button
const [transcript, setTranscript] = useState('');
const clearTranscript = () => {
setTranscript('');
};
return (
<div>
<SpeechToTextComponent
transcript={transcript}
transcriptChanged={(args: any) => setTranscript(args.transcript)}
/>
<button onClick={clearTranscript}>Clear</button>
</div>
);Pattern: Copy to Clipboard
const copyToClipboard = async () => {
await navigator.clipboard.writeText(transcript);
alert('Copied to clipboard!');
};
return (
<div>
<SpeechToTextComponent
transcriptChanged={(args: any) => setTranscript(args.transcript)}
/>
<button onClick={copyToClipboard}>Copy Transcript</button>
</div>
);Troubleshooting
No transcript appearing
- Check microphone is working
- Verify
allowInterimResultssetting - Ensure microphone permissions are granted
- Check browser console for errors
Wrong language recognized
- Verify
langproperty is set to correct language code - Test with your microphone and audio
- Try a different accent or speech pace
Troubleshooting and Security
Table of Contents
- Common Issues and Solutions
- Browser Compatibility
- Microphone Permission Handling
- Security Considerations
- Privacy and Data Handling
- Performance Optimization
- Offline Fallbacks
Common Issues and Solutions
Issue: Component doesn't render
Problem: SpeechToText component not showing on page
Solutions: 1. Check CSS imports
import '@syncfusion/ej2-react-inputs/styles/material.css';
import '@syncfusion/ej2-icons/styles/material.css';2. Verify component is imported
import { SpeechToTextComponent } from '@syncfusion/ej2-react-inputs';3. Check license key if in production
import { registerLicense } from '@syncfusion/ej2-base';
registerLicense('YOUR_LICENSE_KEY');4. Check browser console for errors using DevTools
Issue: Microphone button not working
Problem: Button doesn't respond to clicks
Solutions: 1. Check microphone permissions (see Microphone Permission Handling) 2. Verify browser supports Web Speech API 3. Check for JavaScript errors in console 4. Try refreshing the page
Issue: Speech not being recognized
Problem: Component listens but doesn't transcribe text
Solutions: 1. Check microphone volume - Speak louder 2. Verify language setting - Ensure correct language code
<SpeechToTextComponent lang="en-US" /> // en-US, not just "en"3. Check microphone quality - Test microphone with browser settings 4. Speak clearly and pause - Avoid overlapping words 5. Verify browser support - Check browser compatibility matrix
Issue: Transcript not updating
Problem: transcriptChanged event not firing
Solutions: 1. Verify event handler is properly bound
const handleTranscript = (args: TranscriptChangedEventArgs) => {
console.log(args.transcript);
};
<SpeechToTextComponent transcriptChanged={handleTranscript} />2. Check if component is in listening state 3. Enable interim results
<SpeechToTextComponent allowInterimResults={true} />Issue: Intermittent recognition failures
Problem: Works sometimes, fails other times
Solutions: 1. Check network connectivity (required for browser APIs) 2. Verify microphone is detected
const handleError = (args: ErrorEventArgs) => {
if (args.error === 'audio-capture') {
console.log('Microphone not found');
}
};3. Add retry logic
let retryCount = 0;
const maxRetries = 3;
const handleError = (args: ErrorEventArgs) => {
if (retryCount < maxRetries) {
retryCount++;
speechRef.current?.startListening();
}
};Issue: Slow performance or lag
Problem: Component feels sluggish or updates are delayed
Solutions: 1. Disable interim results if not needed
<SpeechToTextComponent allowInterimResults={false} />2. Use debouncing for transcript updates
const debounce = (func: Function, delay: number) => {
let timeoutId: any;
return (...args: any[]) => {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => func(...args), delay);
};
};
const debouncedUpdate = debounce((text: string) => {
setTranscript(text);
}, 300);3. Optimize component re-renders using React.memo
Browser Compatibility
Supported Browsers
| Browser | Status | Notes |
|---|---|---|
| Chrome | ✅ Fully Supported | Best support, recommended |
| Edge | ✅ Fully Supported | Good support |
| Firefox | ⚠️ Limited | Basic support, may require flags |
| Safari | ✅ Supported | iOS 14.5+ supported |
| Opera | ✅ Supported | Based on Chromium |
| IE 11 | ❌ Not Supported | Not supported |
Checking Browser Support
import { SpeechToTextComponent } from '@syncfusion/ej2-react-inputs';
import { useState, useEffect } from 'react';
function BrowserCheckDemo() {
const [isSupported, setIsSupported] = useState(true);
useEffect(() => {
const SpeechRecognition = (window as any).SpeechRecognition ||
(window as any).webkitSpeechRecognition;
setIsSupported(!!SpeechRecognition);
}, []);
if (!isSupported) {
return (
<div style={{ padding: '20px', backgroundColor: '#ffebee', color: '#c62828' }}>
Your browser does not support the Speech Recognition API.
Please use Chrome, Edge, or Safari.
</div>
);
}
return <SpeechToTextComponent />;
}
export default BrowserCheckDemo;Graceful Degradation
function FallbackDemo() {
const [isSupported, setIsSupported] = useState(true);
useEffect(() => {
const SpeechRecognition = (window as any).SpeechRecognition ||
(window as any).webkitSpeechRecognition;
setIsSupported(!!SpeechRecognition);
}, []);
if (!isSupported) {
return (
<div>
<p>Speech recognition not supported. Please use text input:</p>
<input type="text" placeholder="Enter text manually" />
</div>
);
}
return <SpeechToTextComponent />;
}
export default FallbackDemo;Microphone Permission Handling
Requesting Permissions
Modern browsers require explicit user permission to access the microphone.
import { SpeechToTextComponent, ErrorEventArgs } from '@syncfusion/ej2-react-inputs';
import { useState } from 'react';
function MicrophonePermissionDemo() {
const [hasPermission, setHasPermission] = useState<boolean | null>(null);
const handleError = (args: ErrorEventArgs) => {
if (args.error === 'not-allowed') {
setHasPermission(false);
}
};
const handleStart = () => {
setHasPermission(true);
};
return (
<div>
<SpeechToTextComponent
onStart={handleStart}
onError={handleError}
/>
{hasPermission === false && (
<div style={{
padding: '10px',
marginTop: '10px',
backgroundColor: '#ffebee',
borderLeft: '4px solid #f44336'
}}>
<p>🔒 Microphone permission denied</p>
<p>To use voice input, please:</p>
<ol>
<li>Click the lock icon in the address bar</li>
<li>Allow microphone access</li>
<li>Refresh the page</li>
</ol>
</div>
)}
</div>
);
}
export default MicrophonePermissionDemo;Checking Permissions at Startup
import { useEffect, useState } from 'react';
function CheckMicrophonePermission() {
const [permission, setPermission] = useState<'granted' | 'denied' | 'prompt' | null>(null);
useEffect(() => {
if (navigator.permissions && navigator.permissions.query) {
navigator.permissions.query({ name: 'microphone' })
.then(permissionStatus => {
setPermission(permissionStatus.state as any);
});
}
}, []);
return (
<div>
Microphone Permission: {permission || 'Checking...'}
</div>
);
}Security Considerations
1. HTTPS Requirement
Speech recognition requires secure context (HTTPS):
// ✅ Works
// https://example.com
// ❌ Doesn't work
// http://example.com (except localhost for development)Solution: Always use HTTPS in production
if (location.protocol !== 'https:' && location.hostname !== 'localhost') {
// Redirect to HTTPS or show warning
console.warn('Speech recognition requires HTTPS');
}2. Content Security Policy (CSP)
Ensure your CSP allows Web Speech API:
// In your HTML head:
// <meta http-equiv="Content-Security-Policy"
// content="default-src 'self'; ...">3. Third-Party Data Processing
Audio is sent to third-party servers for processing:
// Inform users
function SecureVoiceApp() {
return (
<div>
<p>⚠️ Your voice data will be processed by Google's servers for transcription.</p>
<SpeechToTextComponent />
</div>
);
}4. Input Sanitization
Always sanitize transcript before using:
import { TextAreaComponent } from '@syncfusion/ej2-react-inputs';
import { useState } from 'react';
function SanitizedTranscript() {
const [transcript, setTranscript] = useState('');
const sanitizeText = (text: string): string => {
const div = document.createElement('div');
div.textContent = text;
return div.innerHTML;
};
const handleTranscript = (args: any) => {
setTranscript(sanitizeText(args.transcript));
};
return (
<div>
<SpeechToTextComponent transcriptChanged={handleTranscript} />
<TextAreaComponent value={transcript} />
</div>
);
}Privacy and Data Handling
1. Inform Users
Clearly communicate data usage:
function PrivacyNotice() {
return (
<div style={{ backgroundColor: '#e3f2fd', padding: '10px', marginBottom: '10px' }}>
<strong>Privacy Notice:</strong>
<p>Your voice input will be sent to external servers for speech-to-text processing.
By using this feature, you agree to their privacy policies.</p>
</div>
);
}2. User Consent
Implement consent mechanism:
import { useState } from 'react';
function ConsentRequiredDemo() {
const [hasConsent, setHasConsent] = useState(false);
if (!hasConsent) {
return (
<div style={{ padding: '20px', border: '1px solid #ddd' }}>
<p>This app uses voice recognition which sends audio to external servers.</p>
<button onClick={() => setHasConsent(true)}>I Agree</button>
<button>Cancel</button>
</div>
);
}
return <SpeechToTextComponent />;
}3. Data Minimization
Don't store voice data longer than needed:
import { useState } from 'react';
function DataMinimization() {
const [transcript, setTranscript] = useState('');
const clearData = () => {
setTranscript('');
};
const downloadTranscript = () => {
const element = document.createElement('a');
element.href = 'data:text/plain;charset=utf-8,' + encodeURIComponent(transcript);
element.download = 'transcript.txt';
element.click();
};
return (
<div>
<SpeechToTextComponent
transcriptChanged={(args: any) => setTranscript(args.transcript)}
/>
<button onClick={clearData}>Clear Data</button>
<button onClick={downloadTranscript}>Download</button>
</div>
);
}Performance Optimization
1. Lazy Loading
Load component only when needed:
import { lazy, Suspense } from 'react';
const SpeechComponent = lazy(() =>
import('./SpeechToTextComponent').then(m => ({
default: m.SpeechToTextComponent
}))
);
function App() {
return (
<Suspense fallback={<div>Loading...</div>}>
<SpeechComponent />
</Suspense>
);
}2. Memoization
Prevent unnecessary re-renders:
import { memo } from 'react';
const OptimizedSpeech = memo(({ onTranscript }: any) => (
<SpeechToTextComponent transcriptChanged={onTranscript} />
));3. Optimize Transcript Updates
const handleTranscript = (args: TranscriptChangedEventArgs) => {
// Only update state on final results (isInterimResult is false when result is final)
if (!args.isInterimResult) {
setFinalTranscript(args.transcript);
}
};
return (
<SpeechToTextComponent
allowInterimResults={false}
transcriptChanged={handleTranscript}
/>
);Offline Fallbacks
1. Detect Offline Status
import { useEffect, useState } from 'react';
function OfflineAwareApp() {
const [isOnline, setIsOnline] = useState(navigator.onLine);
useEffect(() => {
const handleOnline = () => setIsOnline(true);
const handleOffline = () => setIsOnline(false);
window.addEventListener('online', handleOnline);
window.addEventListener('offline', handleOffline);
return () => {
window.removeEventListener('online', handleOnline);
window.removeEventListener('offline', handleOffline);
};
}, []);
if (!isOnline) {
return (
<div style={{ padding: '20px', backgroundColor: '#fff3e0' }}>
🌐 You are offline. Speech recognition is not available.
</div>
);
}
return <SpeechToTextComponent />;
}2. Text Input Fallback
import { useState } from 'react';
function VoiceWithFallback() {
const [useVoice, setUseVoice] = useState(true);
const [transcript, setTranscript] = useState('');
return (
<div>
<div style={{ marginBottom: '10px' }}>
<input
type="radio"
name="input"
checked={useVoice}
onChange={() => setUseVoice(true)}
/>
<label>Voice Input</label>
<input
type="radio"
name="input"
checked={!useVoice}
onChange={() => setUseVoice(false)}
/>
<label>Text Input</label>
</div>
{useVoice ? (
<SpeechToTextComponent
transcriptChanged={(args: any) => setTranscript(args.transcript)}
/>
) : (
<input
type="text"
value={transcript}
onChange={(e) => setTranscript(e.target.value)}
placeholder="Enter text..."
/>
)}
</div>
);
}3. Cache Transcripts
import { useState, useEffect } from 'react';
function CachedTranscripts() {
const [transcripts, setTranscripts] = useState<string[]>([]);
const saveTranscript = (text: string) => {
setTranscripts(prev => [...prev, text]);
localStorage.setItem('transcripts', JSON.stringify([...transcripts, text]));
};
useEffect(() => {
const cached = localStorage.getItem('transcripts');
if (cached) {
setTranscripts(JSON.parse(cached));
}
}, []);
return (
<div>
<SpeechToTextComponent
transcriptChanged={(args: any) => saveTranscript(args.transcript)}
/>
<h3>Saved Transcripts:</h3>
<ul>
{transcripts.map((t, i) => <li key={i}>{t}</li>)}
</ul>
</div>
);
}Best Practices Summary
✅ Do:
- Use HTTPS in production
- Inform users about data handling
- Test on multiple browsers
- Implement error handling
- Provide text input fallback
- Sanitize all user input
- Request microphone permission
❌ Don't:
- Use HTTP for speech features
- Store voice data unnecessarily
- Ignore browser compatibility
- Proceed without error handling
- Forget accessibility features
- Process untrusted data
Related skills
How it compares
Pick syncfusion-react-speech-to-text over raw Web Speech API guides when you need Syncfusion button styling, typed events, and localization for Essential Studio input components.
FAQ
Which events does syncfusion-react-speech-to-text document?
syncfusion-react-speech-to-text covers created, onStart, onStop, onError, and transcriptChanged handlers with typed args including cancel, isInteracted, listeningState, errorMessage, and isInterimResult for interim versus final transcripts.
How do you control listening programmatically?
syncfusion-react-speech-to-text uses a React ref on SpeechToTextComponent and calls startListening() or stopListening() methods. The destroy() method releases component resources when unmounting voice UI.
What browsers support syncfusion-react-speech-to-text?
syncfusion-react-speech-to-text relies on the Web Speech API supported in Chrome, Edge, and Safari. The troubleshooting reference covers microphone permission denials, missing CSS imports, and unsupported browser fallbacks.