Syncfusion AI Assistant

How can I help you?

Speech recognition in EJ2 TypeScript SpeechToText control

3 Feb 202624 minutes to read

Retrieving transcripts

The transcript property allows you to retrieve the transcribed text generated from the spoken input.

import { SpeechToText, TextArea, TranscriptChangedEventArgs } from "@syncfusion/ej2-inputs";

const transcript = 'Hi, hello! How are you?';

// Initializes the SpeechToText control
const speechToText: SpeechToText = new SpeechToText({
    transcript: transcript,
    transcriptChanged: (args: TranscriptChangedEventArgs) => {
        textareaObj.value = speechToText.transcript;
    }
});

// Render initialized SpeechToText.
speechToText.appendTo('#speechtotext_default');

var textareaObj: TextArea = new TextArea({
    rows: 5,
    cols: 50,
    value: speechToText.transcript,
    resizeMode: 'None',
    placeholder: 'Transcribed text will be shown here...'
});
textareaObj.appendTo('#textareaInst');
<!DOCTYPE html>
<html lang="en">

<head>
    <title>Essential JS 2 - SpeechToText</title>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
    <meta name="description" content="Essential JS 2" />
    <meta name="author" content="Syncfusion" />
    <link href="https://cdn.syncfusion.com/ej2/33.1.44/ej2-base/styles/tailwind3.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/33.1.44/ej2-buttons/styles/tailwind3.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/33.1.44/ej2-popups/styles/tailwind3.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/33.1.44/ej2-inputs/styles/tailwind3.css" rel="stylesheet" />

    <!--style reference from app-->
    <link href="index.css" rel="stylesheet" />

    <!--system js reference and configuration-->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/0.19.38/system.js"></script>
    <script src="systemjs.config.js"></script>
</head>
<body>
    <div id='loader'>LOADING....</div>
    <div id="container">
        <button id="speechtotext_default"></button>
        <textarea id="textareaInst"></textarea>
    </div>
</body>
<style>
    #container {
        margin: 50px auto;
        gap: 20px;
        display: flex;
        flex-direction: column;
        align-items: center;
    }
</style>

</html>

Setting language

The lang property specifies the language for speech recognition, ensuring the engine correctly interprets spoken words for a given locale (e.g., en-US for American English or fr-FR for French).

import { SpeechToText, TextArea, TranscriptChangedEventArgs } from "@syncfusion/ej2-inputs";

// Initializes the SpeechToText control
const speechToText: SpeechToText = new SpeechToText({
    lang: 'fr-FR',
    transcriptChanged: (args: TranscriptChangedEventArgs) => {
        textareaObj.value = args.transcript;
    }
});

// Render initialized SpeechToText.
speechToText.appendTo('#speechtotext_default');

var textareaObj: TextArea = new TextArea({
    rows: 5,
    cols: 50,
    value: '',
    resizeMode: 'None',
    placeholder: 'Transcribed text will be shown here...'
});
textareaObj.appendTo('#textareaInst');
<!DOCTYPE html>
<html lang="en">

<head>
    <title>Essential JS 2 - SpeechToText</title>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
    <meta name="description" content="Essential JS 2" />
    <meta name="author" content="Syncfusion" />
    <link href="https://cdn.syncfusion.com/ej2/33.1.44/ej2-base/styles/tailwind3.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/33.1.44/ej2-buttons/styles/tailwind3.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/33.1.44/ej2-popups/styles/tailwind3.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/33.1.44/ej2-inputs/styles/tailwind3.css" rel="stylesheet" />

    <!--style reference from app-->
    <link href="index.css" rel="stylesheet" />

    <!--system js reference and configuration-->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/0.19.38/system.js"></script>
    <script src="systemjs.config.js"></script>
</head>
<body>
    <div id='loader'>LOADING....</div>
    <div id="container">
        <button id="speechtotext_default"></button>
        <textarea id="textareaInst"></textarea>
    </div>
</body>
<style>
    #container {
        margin: 50px auto;
        gap: 20px;
        display: flex;
        flex-direction: column;
        align-items: center;
    }
</style>

</html>

Allowing interim results

The allowInterimResults property controls whether interim (real-time) or final speech recognition results are provided. When true, results are displayed as the user speaks; otherwise, only the final transcript is shown. This property is true by default.

import { SpeechToText, TextArea, TranscriptChangedEventArgs } from "@syncfusion/ej2-inputs";

// Initializes the SpeechToText control
const speechToText: SpeechToText = new SpeechToText({
    allowInterimResults: false,
    transcriptChanged: (args: TranscriptChangedEventArgs) => {
        textareaObj.value = args.transcript;
    }
});

// Render initialized SpeechToText.
speechToText.appendTo('#speechtotext_default');

var textareaObj: TextArea = new TextArea({
    rows: 5,
    cols: 50,
    value: '',
    resizeMode: 'None',
    placeholder: 'Transcript will be displayed here once speech recognition is complete.'
});
textareaObj.appendTo('#textareaInst');
<!DOCTYPE html>
<html lang="en">

<head>
    <title>Essential JS 2 - SpeechToText</title>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
    <meta name="description" content="Essential JS 2" />
    <meta name="author" content="Syncfusion" />
    <link href="https://cdn.syncfusion.com/ej2/33.1.44/ej2-base/styles/tailwind3.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/33.1.44/ej2-buttons/styles/tailwind3.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/33.1.44/ej2-popups/styles/tailwind3.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/33.1.44/ej2-inputs/styles/tailwind3.css" rel="stylesheet" />

    <!--style reference from app-->
    <link href="index.css" rel="stylesheet" />

    <!--system js reference and configuration-->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/0.19.38/system.js"></script>
    <script src="systemjs.config.js"></script>
</head>
<body>
    <div id='loader'>LOADING....</div>
    <div id="container">
        <button id="speechtotext_default"></button>
        <textarea id="textareaInst"></textarea>
    </div>
</body>
<style>
    #container {
        margin: 50px auto;
        gap: 20px;
        display: flex;
        flex-direction: column;
        align-items: center;
    }
</style>

</html>

Managing listening state

The listeningState property manages and indicates the component’s current status. It can be Inactive (idle), Listening (actively capturing audio), or Stopped (recognition complete). The default state is Inactive.

Inactive

The control is in an idle state with no active speech recognition.

Listening

The control is actively listening, capturing, and transcribing speech, indicated by a stop icon and blinking animation.

Stopped

Denotes that speech recognition has ended, and no further speech is being processed.

The following sample demonstrates the usage of the listeningState property.

import { SpeechToText, SpeechToTextState, StartListeningEventArgs, StopListeningEventArgs } from "@syncfusion/ej2-inputs";

// Initializes the SpeechToText control
const speechToText: SpeechToText = new SpeechToText({
    onStop: (args: StopListeningEventArgs) => {
        updateListeningState(args.listeningState);
    },
    onStart: (args: StartListeningEventArgs) => {
        updateListeningState(args.listeningState);
    },
    listeningState: SpeechToTextState.Inactive
});

// Render initialized SpeechToText.
speechToText.appendTo('#speechtotext_default');

function updateListeningState(state: string) {
    var statusTextElement = document.getElementById("status-text")
    if (statusTextElement) { statusTextElement.innerText = state; }

    var statusBox = document.getElementById("status-box-container");
    var waveform = document.getElementById("waveform-item");
    var instructionText = document.getElementById("instruction-text");

    if (statusBox && waveform && instructionText) {
        if (state === "Listening") {
            statusBox.className = "status-box listening";
            waveform.style.display = "flex";
            instructionText.innerText = "Listening... Speak now!";
        } else if (state === "Stopped") {
            statusBox.className = "status-box stopped";
            waveform.style.display = "none";
            instructionText.innerText = "Recognition Stopped.";
        } else {
            statusBox.className = "status-box inactive";
            waveform.style.display = "none";
            instructionText.innerText = "Click the button to start listening.";
        }
    }
}
<!DOCTYPE html>
<html lang="en">

<head>
    <title>Essential JS 2 - SpeechToText</title>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
    <meta name="description" content="Essential JS 2" />
    <meta name="author" content="Syncfusion" />
    <link href="https://cdn.syncfusion.com/ej2/33.1.44/ej2-base/styles/tailwind3.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/33.1.44/ej2-buttons/styles/tailwind3.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/33.1.44/ej2-popups/styles/tailwind3.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/33.1.44/ej2-inputs/styles/tailwind3.css" rel="stylesheet" />

    <!--style reference from app-->
    <link href="index.css" rel="stylesheet" />

    <!--system js reference and configuration-->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/0.19.38/system.js"></script>
    <script src="systemjs.config.js"></script>
</head>
<body>
    <div id='loader'>LOADING....</div>
    <div id="container">
        <div id="status-box-container" class="status-box inactive">
            <span>Status: <strong id="status-text">Inactive</strong></span>
        </div>
        <button id="speechtotext_default"></button>
        <div class="waveform-container">
            <div id="waveform-item" class="waveform" style="display: none;">
                <span></span><span></span><span></span><span></span><span></span>
            </div>
            <p id="instruction-text">Click the button to start listening.</p>
        </div>
    </div>
</body>
<style>

    .waveform-container {
        margin-top: 20px;
        font-weight: bold;
    }

    .waveform {
        display: flex;
        justify-content: center;
        align-items: center;
        height: 40px;
        gap: 5px;
    }

    .waveform span {
        display: block;
        width: 6px;
        height: 20px;
        background: #28a745;
        animation: wave-animation 1.2s infinite ease-in-out;
    }

    .waveform span:nth-child(1) {
        animation-delay: 0s;
    }

    .waveform span:nth-child(2) {
        animation-delay: 0.2s;
    }

    .waveform span:nth-child(3) {
        animation-delay: 0.4s;
    }

    .waveform span:nth-child(4) {
        animation-delay: 0.6s;
    }

    .waveform span:nth-child(5) {
        animation-delay: 0.8s;
    }

    @keyframes wave-animation {
        0%, 100% {
            height: 10px;
        }

        50% {
            height: 30px;
        }
    }

    #container {
        text-align: center;
        margin: 50px auto;
        max-width: 400px;
        padding: 20px;
        border-radius: 10px;
        box-shadow: 0px 4px 10px rgba(0, 0, 0, 0.1);
        background: #fff;
    }

    .status-box {
        padding: 10px;
        border-radius: 5px;
        margin-bottom: 40px;
        font-weight: bold;
    }

    .status-box.listening {
        background-color: #d1e7dd;
        color: #0f5132;
    }

    .status-box.stopped {
        background-color: #f8d7da;
        color: #842029;
    }

    .status-box.inactive {
        background-color: #e2e3e5;
        color: #6c757d;
    }

    .visual-indicator {
        margin-top: 20px;
    }

</style>

</html>

Show or hide tooltip

The showTooltip property determines whether to display a tooltip when hovering over the SpeechToText button. It is enabled by default.

import { SpeechToText, TextArea, TranscriptChangedEventArgs } from "@syncfusion/ej2-inputs";

// Initializes the SpeechToText control
const speechToText: SpeechToText = new SpeechToText({
    showTooltip: false,
    transcriptChanged: (args: TranscriptChangedEventArgs) => {
        textareaObj.value = args.transcript;
    }
});

// Render initialized SpeechToText.
speechToText.appendTo('#speechtotext_default');

var textareaObj: TextArea = new TextArea({
    rows: 5,
    cols: 50,
    value: '',
    resizeMode: 'None',
    placeholder: 'Transcribed text will be shown here...'
});
textareaObj.appendTo('#textareaInst');
<!DOCTYPE html>
<html lang="en">

<head>
    <title>Essential JS 2 - SpeechToText</title>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
    <meta name="description" content="Essential JS 2" />
    <meta name="author" content="Syncfusion" />
    <link href="https://cdn.syncfusion.com/ej2/33.1.44/ej2-base/styles/tailwind3.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/33.1.44/ej2-buttons/styles/tailwind3.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/33.1.44/ej2-popups/styles/tailwind3.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/33.1.44/ej2-inputs/styles/tailwind3.css" rel="stylesheet" />

    <!--style reference from app-->
    <link href="index.css" rel="stylesheet" />

    <!--system js reference and configuration-->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/0.19.38/system.js"></script>
    <script src="systemjs.config.js"></script>
</head>
<body>
    <div id='loader'>LOADING....</div>
    <div id="container">
        <button id="speechtotext_default"></button>
        <textarea id="textareaInst"></textarea>
    </div>
</body>
<style>
    #container {
        margin: 50px auto;
        gap: 20px;
        display: flex;
        flex-direction: column;
        align-items: center;
    }
</style>

</html>

Setting disabled

The disabled property, when set to true, disables the SpeechToText component and prevents user interaction. By default, it is false.

import { SpeechToText, TextArea, TranscriptChangedEventArgs } from "@syncfusion/ej2-inputs";

// Initializes the SpeechToText control
const speechToText: SpeechToText = new SpeechToText({
    disabled: true,
    transcriptChanged: (args: TranscriptChangedEventArgs) => {
        textareaObj.value = args.transcript;
    }
});

// Render initialized SpeechToText.
speechToText.appendTo('#speechtotext_default');

var textareaObj: TextArea = new TextArea({
    rows: 5,
    cols: 50,
    value: '',
    resizeMode: 'None',
    placeholder: 'Transcribed text will be shown here...'
});
textareaObj.appendTo('#textareaInst');
<!DOCTYPE html>
<html lang="en">

<head>
    <title>Essential JS 2 - SpeechToText</title>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
    <meta name="description" content="Essential JS 2" />
    <meta name="author" content="Syncfusion" />
    <link href="https://cdn.syncfusion.com/ej2/33.1.44/ej2-base/styles/tailwind3.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/33.1.44/ej2-buttons/styles/tailwind3.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/33.1.44/ej2-popups/styles/tailwind3.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/33.1.44/ej2-inputs/styles/tailwind3.css" rel="stylesheet" />

    <!--style reference from app-->
    <link href="index.css" rel="stylesheet" />

    <!--system js reference and configuration-->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/0.19.38/system.js"></script>
    <script src="systemjs.config.js"></script>
</head>
<body>
    <div id='loader'>LOADING....</div>
    <div id="container">
        <button id="speechtotext_default"></button>
        <textarea id="textareaInst"></textarea>
    </div>
</body>
<style>
    #container {
        margin: 50px auto;
        gap: 20px;
        display: flex;
        flex-direction: column;
        align-items: center;
    }
</style>

</html>

Setting HTML Attributes

You can use the htmlAttributes property to assign custom attributes to the SpeechToText control for the button element.

Error Handling

The SpeechToText control handles various errors that may occur during speech recognition. The following table lists the possible errors and their causes:

Error Cause
no-speech The microphone did not detect any speech input.
aborted The speech recognition process was intentionally terminated.
audio-capture The system was unable to detect a microphone device.
not-allowed Access to the microphone was denied by the user or browser settings.
service-not-allowed The current context does not permit the use of the speech recognition service.
network A network issue is preventing the speech recognition service from functioning.
unsupported-browser The browser being used does not support the SpeechRecognition API.
default An unidentified error occurred during the speech recognition process.

Browser Support

The SpeechToText control relies on the Speech Recognition API for processing speech input. Ensure that the browser supports this API before implementation.

Browser Supported versions
Chrome 25+
Edge 79+
Firefox Not Supported
Safari 12+
Opera 30+