Important: This documentation covers Yarn 1 (Classic).
For Yarn 2+ docs and migration guide, see yarnpkg.com.

Package detail

react-say

compulim29.9kMIT2.1.0

npm version Build Status

react, speak, speech synthesis, speechsynthesis, text to speech, tts, utterance, web speech, webspeech

readme

react-say

npm version Build Status

A React component that synthesis text into speech using Web Speech API.

Demo

Try out the demo at https://compulim.github.io/react-say/.

How to use

First, run npm install react-say for production build. Or run npm install react-say@master for latest development build.

Synthesizing an utterance

react-say offer comprehensive ways to synthesize an utterance:

Using <Say> component

The following will speak the text immediately upon showing up. Some browsers may not speak the text until the user interacted with the page.

import React from 'react';
import Say from 'react-say';

export default () =>
  <Say speak="A quick brown fox jumped over the lazy dogs." />

Customizing pitch/rate/volume

To modify the speech by varying pitch, rate, and volume. You can use <Say> to say your text.

import React from 'react';
import Say from 'react-say';

export default () =>
  <Say
    pitch={ 1.1 }
    rate={ 1.5 }
    speak="A quick brown fox jumped over the lazy dogs."
    volume={ .8 }
  />

Selecting voice

To select different voice for synthesis, you can either pass a SpeechSynthesisVoice object or a selector function to the voice props`.

For selector function, the signature is (voices: SpeechSynthesisVoice[]) => SpeechSynthesisVoice.

import React, { useCallback } from 'react';
import Say from 'react-say';

export default () => {
  // Depends on Web Speech API used, the first argument may be an array-like object instead of an array.
  // We convert it to an array before performing the search.
  const selector = useCallback(voices => [...voices].find(v => v.lang === 'zh-HK'), []);

  return (
    <Say
      speak="A quick brown fox jumped over the lazy dogs."
      voice={ selector }
    />
  );
}

Note: it also works with <SayButton>.

Using <SayButton> component

If you want the web page to say something when the user click on a button, you can use the <SayButton>.

import React from 'react';
import { SayButton } from 'react-say';

export default props =>
  <SayButton
    onClick={ event => console.log(event) }
    speak="A quick brown fox jumped over the lazy dogs."
  >
    Tell me a story
  </SayButton>

Using <SayUtterance> component

Instead of synthesizing a text, you can prepare your own SpeechSynthesisUtterance object instead.

import React, { useMemo } from 'react';
import { SayUtterance } from 'react-say';

export default () => {
  const utterance = useMemo(() => new SpeechSynthesisUtterance('A quick brown fox jumped over the lazy dogs.'), []);

  return (
    <SayUtterance
      utterance={ utterance }
    />
  );
}

Using useSynthesize hook

If you want to build your own component to use speech synthesis, you can use useSynthesize hook.

import React, { useCallback } from 'react';
import { useSynthesize } from 'react-say';

export default () => {
  const synthesize = useSynthesize();
  const handleClick = useCallback(() => {
    synthesize('A quick brown fox jumped over the lazy dogs.');
  }, [synthesize]);

  return (
    <button onClick={ handleClick }>Tell me a story</button>
  );
}

Cancelling an active or pending synthesis

Once you call synthesize() function, the utterance will be queued. The queue prevent multiple utterances to be synthesized at the same time. You can call cancel() to remove the utterance from the queue. If the utterance is being synthesized, it will be aborted.

import React, { useEffect } from 'react';
import { useSynthesize } from 'react-say';

export default () => {
  const synthesize = useSynthesize();

  // When this component is mounted, the utterance will be queued immediately.
  useEffect(() => {
    const { cancel } = synthesize('A quick brown fox jumped over the lazy dogs.');

    // When this component is unmounted, the synthesis will be cancelled.
    return () => cancel();
  }, [synthesize]);

  return (
    <button onClick={ handleClick }>Tell me a story</button>
  );
}

Bring your own SpeechSynthesis

You can bring your own window.speechSynthesis and window.speechSynthesisUtterance for custom speech synthesis. For example, you can bring Azure Cognitive Services Speech Services thru web-speech-cognitive-services package.

import Say from 'react-say';
import createPonyfill from 'web-speech-cognitive-services/lib/SpeechServices';

export default () => {
  // You are recommended to use authorization token instead of subscription key.
  const ponyfill = useMemo(() => createPonyfill({
    region: 'westus',
    subscriptionKey: 'YOUR_SUBSCRIPTION_KEY'
  }), []);

  return (
    <Say
      ponyfill={ ponyfill }
      speak="A quick brown fox jumped over the lazy dogs."
    />
  );
}

Caveats

  • Instead of using the native queue for utterances, we implement our own speech queue for browser compatibility reasons
    • Queue is managed by <Composer>, all <Say>, <SayButton>, and <SayUtterance> inside the same <Composer> will share the same queue
    • Native queue does not support partial cancel, when cancel is called, all pending utterances are stopped
    • If <Say> or <SayButton> is unmounted, the utterance can be stopped without affecting other pending utterances
    • Utterance order can be changed on-the-fly
  • Browser quirks
    • Chrome: if cancel and speak are called repeatedly, speak will appear to succeed (speaking === true) but audio is never played (start event is never fired)
    • Safari: when speech is not triggered by user event (e.g. mouse click or tap), the speech will not be played
      • Workaround: on page load, prime the speech engine by any user events

Roadmap

  • <input checked="" disabled="" type="checkbox"> Prettify playground page

Contributions

Like us? Star us.

Want to make it better? File us an issue.

Don't like something you see? Submit a pull request.

changelog

Changelog

All notable changes to this project will be documented in this file.

The format is based on Keep a Changelog and this project adheres to Semantic Versioning.

[Unreleased]

[2.1.0] - 2021-10-14

Changed

[2.0.1] - 2020-08-06

Fixed

  • Use new CustomEvent() and fallback to document.createElement for custom events, by @compulim, in PR #22, #23, and #24

[2.0.0] - 2019-11-19

Breaking changes

  • Now requires React 16.8.6 or up
  • Updates to <Say> component
    • Renamed prop speak to text
    • Will no longer renders its children
  • Updates to <SayButton> component
    • Renamed prop speak to text
  • Composer signature is being updated
    • New synthesize function to replace speak and cancel
      • When called, it will return { cancel: Function, promise: Promise }
      • cancel, when called, will cancel the utterance. If the utterance is being synthesized, it will be stopped abruptly
      • promise will be resolved when the utterance is synthesized or errored
    • cancel and speak is removed because the newer synthesize function offer same functionality with simplified interface
  • All React components now accepts ponyfill instead of speechSynthesis and speechSynthesisUtterance
    • Using browser speech would become as simple as <Say ponyfill={ window }>

Changed

  • Update build scripts to publish /packages/component/package.json, by @compulim in PR #17
  • Rework of all components, by @compulim in PR #17
    • Support nested <Context> and <Composer>
      • Nested context will share the same queue, with different ponyfills
      • If not ponyfill is specified, it will inherit from its parent, or default to browser-based speech
      • Upgraded <Composer> component from class component to functional component
    • Added new useSynthesize() hook, which returns a function to queue an utterance
      • synthesize(utteranceOrText: (SpeechSynthesisUtterance | string), progressFn: () => void) => void
    • New <SayUtterance> component to synthesis SpeechSynthesisUtterance instead of text
      • <Say> is being refactored to use <SayUtterance> to simplify the codebase
      • <SayButton> is being refactored to use <Say> to simplify the codebase
    • 🔥 Updates to <Say> component
      • Renamed prop speak to text
      • Will no longer renders its children
    • 🔥 Updates to <SayButton> component
      • Renamed prop speak to text
    • 🔥 Composer signature is being updated
      • New synthesize function to replace speak and cancel
        • When called, it will return { cancel: Function, promise: Promise }
        • cancel, when called, will cancel the utterance. If the utterance is being synthesized, it will be stopped abruptly
        • promise will be resolved when the utterance is synthesized or errored
      • cancel and speak is removed because the newer synthesize function offer same functionality with simplified interface
    • 🔥 All React components now accepts ponyfill instead of speechSynthesis and speechSynthesisUtterance
      • Using browser speech would become as simple as <Say ponyfill={ window }>
  • Bumped dependencies in PR #18

[1.2.0] - 2019-05-28

Changed

Fixed

  • Fix #8 by removing workaround for Chrome bug, in PR #7
    • The workaround caused unnecessary kill-and-retry if the speech synthesizer legitimately took more than a second to signal start event

[1.1.1] - 2018-10-31

Changed

[1.1.0] - 2018-10-28

Added

  • Utterance queue are now controlled by <Composer> instance, instead of native speechSynthesis for better browser compatibility
    • Chrome: does not fire start and end events if speak/cancel are called too fast
    • Safari: does not play audio or start event if the first utterance is not triggered by user event
  • Unmounting elements will cancel the speech in progress or pending speech

Changed

Fixed

  • Null reference on props.speechSynthesis

[1.0.0] - 2018-07-09

Added

  • Initial release