spoken-text
0:00/0:00

Reference

Everything the package exports, and nothing it does not. Where a page has more to say about one of these, it is linked from the row.

<SpokenText>

children
string | ReactNode

A passage, or a tree of elements. Each block becomes its own alignment request. Reading a whole document.

speech
SpokenTextController

A controller from useSpokenText. Left out, it reads a provider, or else manages itself.

skip
(string | ((el) => boolean))[] = DEFAULT_SKIP

Parts of the tree to leave unspoken. They still render.

only
(string | ((el) => boolean))[]

Speak only these parts of the tree. Unset means all of it.

say
Record<string, SayRule>

Words to speak that are not on the page: a section number, alt text, a note where something was skipped. Saying what is not on the page.

as
"p" | "div" | "span" | … = "div" / "p"

Element it renders into: div for a tree, p for a string.

className
string

Class on that element.

classNames
{ word, past, current, future, separator }

Classes for the words and for the gaps between them. Setting one drops the built-in look for that slot, so your CSS wins. Styling the highlight.

renderWord
(word: DisplayWord) => ReactNode

Render words yourself. Whitespace is still inserted for you.

seekOnWordClick
boolean = true

Click a word to play from there, fetching its block if it has not been asked for.

endpoint
string = "/api/transcription"

Route that turns text into audio and timings.

fetchAlignment
(text, { kind }) => Promise<Alignment>

Skip endpoint and resolve the alignment however you like.

onWordChange
(index: number, word?: DisplayWord) => void

Fires when the spoken word changes. -1 means nothing is spoken yet.

debounceMs
number = 0

Wait this long after children stops changing before fetching. Useful behind a textarea.

autoPlay
boolean = false

Start speaking as soon as the audio is ready.

Every word also carries data-spoken-state and data-spoken-index, so plain CSS can style the highlight without any props at all.

<Player>

speech
SpokenTextController

The controller to drive. Left out, it reads a provider.

className
string

Class on the wrapper.

classNames
{ root, button, track, elapsed, thumb, time, status }

Per-part classes, same "your class wins" rule. Styling the highlight.

showTime
boolean = true

Show elapsed / total time.

showStatus
boolean = true

Show the loading and error line.

While blocks are still loading the total is an estimate, and the player says so: ~1:42, dimmed, correcting itself as the audio lands.

<SpokenTextProvider>

children
ReactNode

One document, and any number of players for it.

options
endpoint · fetchAlignment · onWordChange · debounceMs · autoPlay

The same options the hook takes, applied to the whole document. Anything written on the <SpokenText> inside it wins, so a debounceMs can sit next to the text it is about.

useSpokenText(text, options?)

Takes the same options as <SpokenText>. Pass null as the text to switch it off. It returns a SpokenTextController.

useSpokenTextController()

Returns the controller the nearest <SpokenTextProvider> is holding, for building a player of your own. Outside a provider it returns nothing.

SpokenTextController

text
string

The document as one string, blocks joined.

words
DisplayWord[]

Every word, in order, across every block.

currentWordIndex, currentWord
number, DisplayWord | undefined

The word being spoken, across the document, or -1 and undefined.

segments
{ start, end, kind, status }[]

One per block, as a range over words. status is "idle" until the block has been asked for.

status, isLoading, isPlaying, error

What it is doing right now.

currentTime, duration, audioUrl

Playback position and source.

durationIsEstimate
boolean

True while duration still counts unloaded blocks at a reading pace. It settles as their audio lands.

play, pause, toggle
() => void

Playback.

seek, seekToWord, seekToFraction
(number) => void

Move the playhead, anywhere in the document.

getAudioElement
() => HTMLAudioElement | null

The underlying Audio, for anything the API misses.

DisplayWord

text
string

The word exactly as it appeared in the source text.

index
number

Its position in the whole document.

state
"past" | "current" | "future"

Where it sits relative to the playhead.

seekable
boolean

True when the word has a timestamp. Words in a block nobody has asked for yet are untimed, and clicking one fetches that block.

hidden
boolean

True for a word a say rule added: spoken, timed like any other word, and never rendered.

start, end
number | undefined

Seconds from the start of the document, not of the block.

SayRule

(info: SayInfo) => SayResult. SayInfo is { text, element, count, kind }: what the element says on its own, the element itself, how many elements this rule has matched so far, and what kind of block it is. SayResult is a string, which replaces those words, or { before?, after? }, which keeps them and speaks around them, or nothing, which changes nothing. All three types are exported. Saying what is not on the page.

BlockKind

"heading" | "paragraph" | "list" | "quote". What a block is, so a voice can read a title like a title. Headings are h1–h6, list items are li, quotes are blockquote, and everything else is a paragraph. It travels with the text to the route and is part of the cache key.

Also exported

DEFAULT_SKIP
readonly SpokenSelector[]

code, pre, kbd, samp, var, script, style, svg, canvas, iframe, math. Spread it to add to the list rather than replace it.

DEFAULT_ENDPOINT
"/api/transcription"

Where a passage is posted unless endpoint says otherwise.

createEndpointAligner
(endpoint) => FetchAlignment

The default aligner, built by hand. A starting point for wrapping the POST.

clearAlignmentCache
() => void

Empties the in-memory cache that keeps one passage from being fetched twice on a page.

tokenize
(text) => Tokens

Words, separators and leading whitespace: how a passage is split.

alignTokens
(tokens, words) => SpokenSpan[]

Match rendered tokens to transcribed words. The whole of how words are matched to timings.

normalizeForAlignment
(text) => string

Letters and digits only, casefolded, accents folded. What the two sides are compared on.

tokenIndexAt
(spans, time) => number

Which token is being spoken at a given second.

From spoken-text/server:

createAlignmentHandler

The route.

elevenlabsSpeech, openaiSpeech, openaiTranscription

The bundled speech and transcription adapters.

vercelBlobCache

The bundled cache.

sha256Hex
(text) => Promise<string>

What the default hash is built from.