SpeechSynthesis

Reactive wrapper around the Speech Synthesis API. Convert text to speech with Angular signals.

Loading demo...

Usage

angular-ts
import { Component, signal } from '@angular/core';
import { speechSynthesis } from '@signality/core';

@Component({
  template: `
    <input [(ngModel)]="text" />
    <button
      (click)="speech.speak(text())"
      [disabled]="speech.isSpeaking()"
    >
      Speak
    </button>
    <button
      (click)="speech.stop()"
      [disabled]="!speech.isSpeaking()"
    >
      Stop
    </button>
  `,
})
export class TextToSpeech {
  readonly speech = speechSynthesis(); 
  readonly text = signal('Hello, world!');
}

Parameters

ParameterTypeDescription
optionsSpeechSynthesisOptionsOptional configuration (see Options below)

Options

All options support reactive values via MaybeSignal<T> — pass a plain value or an Angular signal.

OptionTypeDefaultDescription
langMaybeSignal<string>-Language
rateMaybeSignal<number>1Speech rate (0.1 to 10)
pitchMaybeSignal<number>1Pitch (0 to 2)
volumeMaybeSignal<number>1Volume (0 to 1)
voiceMaybeSignal<SpeechSynthesisVoice>-Voice
injectorInjector-Optional injector for DI context

Return Value

The speechSynthesis() function returns a SpeechSynthesisRef object:

PropertyTypeDescription
isSupportedSignal<boolean>Whether Speech Synthesis API is supported
isSpeakingSignal<boolean>Whether speech is currently playing
isPausedSignal<boolean>Whether speech is currently paused
voicesSignal<SpeechSynthesisVoice[]>Available voices
currentTextSignal<string>Current speaking text
speak(text: string) => voidSpeak text
stop() => voidStop speaking
pause() => voidPause speaking
resume() => voidResume speaking

Examples

Reactive options

angular-ts
import { Component, signal } from '@angular/core';
import { speechSynthesis } from '@signality/core';

@Component({
  template: `
    <label>Rate: {{ rate() }}</label>
    <input type="range" min="0.5" max="2" step="0.1" [value]="rate()" (input)="rate.set(+$any($event.target).value)" />

    <label>Pitch: {{ pitch() }}</label>
    <input type="range" min="0" max="2" step="0.1" [value]="pitch()" (input)="pitch.set(+$any($event.target).value)" />

    <button (click)="speech.speak('Hello, world!')">Speak</button>
    <button (click)="speech.stop()">Stop</button>
  `,
})
export class ReactiveOptions {
  readonly rate = signal(1);
  readonly pitch = signal(1);

  readonly speech = speechSynthesis({ 
    rate: this.rate, 
    pitch: this.pitch, 
  }); 
}

Voice selection

angular-ts
import { Component, signal } from '@angular/core';
import { speechSynthesis } from '@signality/core';

@Component({
  template: `
    <select (change)="onVoiceChange($any($event.target).value)">
      @for (voice of speech.voices(); track voice.voiceURI) {
        <option [value]="voice.voiceURI">{{ voice.name }}</option>
      }
    </select>
    <button (click)="speech.speak('Hello, world!')">Speak</button>
  `,
})
export class VoiceSelector {
  readonly selectedVoice = signal<SpeechSynthesisVoice | undefined>(undefined);

  readonly speech = speechSynthesis({
    voice: this.selectedVoice, 
  });

  onVoiceChange(voiceURI: string) {
    const voice = this.speech.voices().find(v => v.voiceURI === voiceURI);
    this.selectedVoice.set(voice);
  }
}

Browser Compatibility

The Speech Synthesis API has limited browser support. Always check isSupported() before using text-to-speech (see Browser API support detection):

angular-html
@if (speech.isSupported()) {
  <button (click)="speech.speak('Hello')">Speak</button>
} @else {
  <p>Text-to-speech is not available in this browser</p>
}

For detailed browser support information, see Can I use: Speech Synthesis API.

SSR Compatibility

On the server, signals initialize with safe defaults:

  • isSupportedfalse
  • isSpeakingfalse
  • isPausedfalse
  • voices[]
  • currentText''
  • speak, stop, pause, resume → no-op functions

Type Definitions

typescript
interface SpeechSynthesisOptions extends WithInjector {
  readonly lang?: MaybeSignal<string>;
  readonly rate?: MaybeSignal<number>;
  readonly pitch?: MaybeSignal<number>;
  readonly volume?: MaybeSignal<number>;
  readonly voice?: MaybeSignal<SpeechSynthesisVoice>;
}

interface SpeechSynthesisRef {
  readonly isSupported: Signal<boolean>;
  readonly isSpeaking: Signal<boolean>;
  readonly isPaused: Signal<boolean>;
  readonly voices: Signal<SpeechSynthesisVoice[]>;
  readonly currentText: Signal<string>;
  readonly speak: (text: string) => void;
  readonly stop: () => void;
  readonly pause: () => void;
  readonly resume: () => void;
}

function speechSynthesis(options?: SpeechSynthesisOptions): SpeechSynthesisRef;
Edit this page on GitHub Last updated: Mar 19, 2026, 23:28:23