# react-say

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

Latest version **2.2.1** (published 2025-12-22) · MIT license · 0 weekly downloads

## Install

```sh
npm install react-say
pnpm add react-say
yarn add react-say
bun add react-say
```

## Health

**Score 65/100 (B)** — status: stable.

Positive: has types; esm support; no vulnerabilities; has provenance; high quality score.

Warnings: low downloads.

## Facts

| | |
|---|---|
| Version | 2.2.1 |
| Published | 2025-12-22 |
| First published | 2018-07-04 |
| Weekly downloads | 0 |
| License | MIT |
| TypeScript types | bundled |
| Module format | ESM + CommonJS |
| Dependencies | 2 |
| Unpacked size | 110.3 KB |
| Known vulnerabilities | 0 |
| Install scripts | no |
| Provenance | attested (GitHub Actions) |
| GitHub stars | 26 |
| Author | William Wong |
| Maintainers | compulim, spyip |
| Keywords | react, speak, speech synthesis, speechsynthesis, text to speech, tts, utterance, web speech, webspeech |

## Links

- npm: https://www.npmjs.com/package/react-say
- Repository: https://github.com/compulim/react-say
- Homepage: https://github.com/compulim/react-say#readme
- Issues: https://github.com/compulim/react-say/issues
- npm.io page: https://npm.io/package/react-say

## Dependencies (2)

- [react-say](https://npm.io/package/react-say.md) ^2.2.1
- [prop-types](https://npm.io/package/prop-types.md) ^15.8.1

## Alternatives

- [mobx-react](https://npm.io/package/mobx-react.md) — 2.8M weekly downloads
- [rc-tree](https://npm.io/package/rc-tree.md) — 2.6M weekly downloads
- [@react-oauth/google](https://npm.io/package/@react-oauth/google.md) — 1.3M weekly downloads
- [@wagmi/connectors](https://npm.io/package/@wagmi/connectors.md) — 877.0K weekly downloads
- [vee-validate](https://npm.io/package/vee-validate.md) — 836.4K weekly downloads

## Recent versions

- 2.2.1 (latest) — 2025-12-22
- 2.2.2-main.202601020228.e3983f8 (main) — 2026-01-02
- 2.2.2-main.202601020220.0f82828 — 2026-01-02
- 2.2.2-main.202512220900.051d11b — 2025-12-22
- 2.2.1-main.202512220840.b2dfe50 — 2025-12-22
- 2.2.1-main.202512220844.a802286 — 2025-12-22
- 2.2.1-main.2e6b114 — 2025-07-20
- 2.2.0-main.2356e8e — 2025-07-20
- 2.2.0 — 2025-07-20
- 2.2.0-main.4564562 — 2025-07-20
- 2.2.0-main.9c5126c — 2025-07-20
- 2.1.1-master.22688e3 — 2021-10-14
- 2.1.0 — 2021-10-14
- 2.0.2-master.c97a22c — 2021-10-14
- 2.0.2-master.ee7cd76 — 2020-08-06
- … 48 more at https://npm.io/package/react-say/versions

## README

# react-say

[![npm version](https://badge.fury.io/js/react-say.svg)](https://badge.fury.io/js/react-say) [![Build Status](https://travis-ci.org/compulim/react-say.svg?branch=master)](https://travis-ci.org/compulim/react-say)

A React component that synthesis text into speech using [Web Speech API](https://developer.mozilla.org/en-US/docs/Web/API/SpeechSynthesis).

# 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:

- [Synthesize text using `<Say>` component](using-say-component)
- [Synthesize text using `<SayButton>` component](using-say-button-component)
- [Synthesize utterance using `<SayUtterance>` component](using-say-utterance-component)
- [Synthesize text or utterance using `useSynthesize` hook](using-use-synthesis-hook)

### 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.

```jsx
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.

```jsx
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`.

```jsx
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>`.

```jsx
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.

```jsx
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.

```jsx
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.

```jsx
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`](https://npmjs.com/package/web-speech-cognitive-services) package.

```jsx
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

* [x] Prettify playground page

# Contributions

Like us? [Star](https://github.com/compulim/react-say/stargazers) us.

Want to make it better? [File](https://github.com/compulim/react-say/issues) us an issue.

Don't like something you see? [Submit](https://github.com/compulim/react-say/pulls) a pull request.

---
_Source: https://npm.io/package/react-say · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
