Skip to content

Streaming Response

A model's response as it is written, that screen readers can follow: each finished sentence is spoken once, then how it ended.

Preview

Can I change my delivery address?

Writing…

Installation

pnpm add @syntara/react @syntara/tokens
import { StreamingResponse, ResponseText, ResponseSources, ResponseSource } from '@syntara/react';

Usage

import { StreamingResponse } from '@syntara/react';

export function Reply({ status, text }) {
  return <StreamingResponse status={status} text={text} />;
}

Examples

Plain text

Ask, watch it write, and stop it part way, with no visual layer.

States

Writing, stopped, failed and complete. The status line is words and a mark, never colour alone, and disappears once complete.

Your statement for September is ready. The largest change since
Writing…
Three plans match what you asked for. The first
Stopped
Here is a summary of the
Couldn't finishThe connection dropped. Try again.
Your password was changed. You'll be asked to sign in again on other devices.

Speak only the start and end

announce="status" for long answers people would rather read at their own pace.

Spending rose in groceries and travel this quarter, while subscriptions fell after two were cancelled. The full breakdown by
Writing…

Accessibility

No keyboard interaction of its own.

  • The visible text is not a live region, so it is never re-read or chopped token by token. A separate polite live region, mounted with the component, speaks updates.
  • Sentences are split with Intl.Segmenter in the locale React Aria reports, so the Hindi danda and the Arabic question mark end sentences. Browsers without it announce at the end only.
  • A failed response's unfinished last sentence is not read out.
  • The status line pairs a mark with words; the writing dot's scale animation is off with reduced motion, its fade stays.
  • Not yet checked with a real screen reader. jsdom proves what is put in the live region, not what VoiceOver or NVDA say.

Guidelines

Do

  • Pass plain text in text and the rendered version as children.
  • Set status to stopped or error when the stream ends early, so people hear that it did.

Don’t

  • Don't wrap it in another aria-live region; it already speaks.
  • Don't use it for text that isn't arriving progressively. Use Alert or Toast for a finished message.

API reference

StreamingResponse

statusRequired
  • streaming
  • complete
  • stopped
  • error

Where the response is. The app owns it; the component never guesses from the text.

textRequired
string

The response so far, as plain text. It is what screen readers hear, so leave out markdown symbols and code.

children
ReactNode

What sighted users see, such as rendered markdown. Defaults to text, with its line breaks kept.

label
string

Accessible name of the article, so it can be found by article navigation.

Default 'Response'

announce
  • sentencesdefault
  • status

sentences speaks each finished sentence as it arrives; status speaks only the start and the end.

announceInterval
number

Shortest gap between two spoken updates while streaming, in ms. Sentences that finish inside it are spoken together.

Default 1000

errorMessage
string

Shown and spoken after the error label when status is error.

startLabel / writingLabel / completeLabel / stoppedLabel / errorLabel
string

Every spoken and shown word, for translation.

Default 'Writing response' / 'Writing…' / 'Response complete' / 'Stopped' / "Couldn't finish"

ResponseText

textRequired
string

The response so far. New words fade in from the brand text colour; a caret glows at the end while the parent streams.

ResponseSources

label
string

Accessible name of the list of sources.

Default 'Sources'

ResponseSource

index
number

The citation number used in the text.

href
string

Where the source lives. Any React Aria Link prop works.

Tokens

The semantic tokens this component reads, grouped by what they control. Swatches show this site’s theme; change a tenant’s brand and the component follows with no code change.

Colour5
text.defaulttext.subtletext.brandfeedback.danger.fgfeedback.danger.bg
Type3
font.size.mdfont.size.smline-height.normal
Space and size2
space.1space.2
Motion2
motion.duration.slowmotion.easing