Skip to content
Sensors

useSpeechSynthesis

Reactive wrapper around the SpeechSynthesis API. Provides speak/stop/toggle controls with real-time status tracking.

Speech Synthesis
Not Supported

Text-to-speech via the SpeechSynthesis API. Click Speak to hear the text.

Status: init
import {
const useSpeechSynthesis: (text: MaybeObservable<string>, options?: DeepMaybeObservable<UseSpeechSynthesisOptions>) => UseSpeechSynthesisReturn
useSpeechSynthesis
} from "@usels/web";
function
function TextToSpeech(): JSX.Element
TextToSpeech
() {
const {
const isSupported$: ReadonlyObservable<boolean>
isSupported$
,
const isPlaying$: ReadonlyObservable<boolean>

Whether speech is currently playing

isPlaying$
,
const status$: ReadonlyObservable<UseSpeechSynthesisStatus>

Current status

status$
,
const speak: () => void

Start speaking the text

speak
,
const stop: () => void

Stop speaking

stop
} =
function useSpeechSynthesis(text: MaybeObservable<string>, options?: DeepMaybeObservable<UseSpeechSynthesisOptions>): UseSpeechSynthesisReturn

Framework-agnostic reactive wrapper around the SpeechSynthesis API.

Each speak() call constructs a fresh SpeechSynthesisUtterance using the latest text and option values. Cleanup (speechSynthesis.cancel()) is registered via onUnmount.

useSpeechSynthesis
("Hello world");
return (
<
JSX.IntrinsicElements.div: DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>
div
>
<
JSX.IntrinsicElements.p: DetailedHTMLProps<HTMLAttributes<HTMLParagraphElement>, HTMLParagraphElement>
p
>Supported: {
const isSupported$: ReadonlyObservable<boolean>
isSupported$
.
ImmutableObservableBase<boolean>.get(trackingType?: TrackingType | GetOptions): {}
get
() ? "Yes" : "No"}</
JSX.IntrinsicElements.p: DetailedHTMLProps<HTMLAttributes<HTMLParagraphElement>, HTMLParagraphElement>
p
>
<
JSX.IntrinsicElements.p: DetailedHTMLProps<HTMLAttributes<HTMLParagraphElement>, HTMLParagraphElement>
p
>Status: {
const status$: ReadonlyObservable<UseSpeechSynthesisStatus>

Current status

status$
.
ImmutableObservableBase<UseSpeechSynthesisStatus>.get(trackingType?: TrackingType | GetOptions): {}
get
()}</
JSX.IntrinsicElements.p: DetailedHTMLProps<HTMLAttributes<HTMLParagraphElement>, HTMLParagraphElement>
p
>
<
JSX.IntrinsicElements.button: DetailedHTMLProps<ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>
button
DOMAttributes<HTMLButtonElement>.onClick?: MouseEventHandler<HTMLButtonElement> | undefined
onClick
={() =>
const speak: () => void

Start speaking the text

speak
()}>Speak</
JSX.IntrinsicElements.button: DetailedHTMLProps<ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>
button
>
<
JSX.IntrinsicElements.button: DetailedHTMLProps<ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>
button
DOMAttributes<HTMLButtonElement>.onClick?: MouseEventHandler<HTMLButtonElement> | undefined
onClick
={() =>
const stop: () => void

Stop speaking

stop
()}>Stop</
JSX.IntrinsicElements.button: DetailedHTMLProps<ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>
button
>
</
JSX.IntrinsicElements.div: DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>
div
>
);
}
// @noErrors
import { useSpeechSynthesis } from "@usels/web";
function CustomVoice() {
const { speak, stop, isPlaying$ } = useSpeechSynthesis("안녕하세요", {
lang: "ko-KR",
pitch: 1.2,
rate: 0.9,
});
return (
<button onClick={() => (isPlaying$.get() ? stop() : speak())}>
{isPlaying$.get() ? "Stop" : "Speak"}
</button>
);
}

The text parameter accepts MaybeObservable<string>, and options accept DeepMaybeObservable. Changes take effect on the next speak() call.

// @noErrors
import { observable, useObservable } from "@usels/core";
import { useSpeechSynthesis } from "@usels/web";
function DynamicSpeech() {
const text$ = useObservable("Hello world");
const rate$ = observable(1);
const { speak } = useSpeechSynthesis(text$, { rate: rate$ });
return (
<div>
<input value={text$.get()} onChange={(e) => text$.set(e.target.value)} />
<button onClick={() => speak()}>Speak</button>
</div>
);
}

text is MaybeObservable<string>. Pass a plain string or an Observable<string>. The latest value is read at each speak() call.

options is DeepMaybeObservable. Each option field can be a plain value or an Observable. All options are read at each speak() call time. The voice option uses opaque wrapping to prevent Legend-State from deep-proxying the DOM object.

ParameterTypeDescription
textMaybeObservable<string>-
optionsUseSpeechSynthesisOptions (optional)-
OptionTypeDefaultDescription
langstring-Language for synthesis. Default: “en-US”
pitchnumber-Pitch (0-2). Default: 1
ratenumber-Rate (0.1-10). Default: 1
volumenumber-Volume (0-1). Default: 1
voiceSpeechSynthesisVoice-Voice to use
windowWindowSource--

UseSpeechSynthesisReturn

NameTypeDescription
isPlaying$ReadonlyObservable<boolean>Whether speech is currently playing
status$ReadonlyObservable<UseSpeechSynthesisStatus>Current status
error$ReadonlyObservable<UseSpeechSynthesisErrorData | undefined>Speech error
speak() => voidStart speaking the text
stop() => voidStop speaking
toggle(value?: boolean | undefined) => voidToggle speaking
isSupported$ReadonlyObservable<boolean>-

View on GitHub