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?
Installation
pnpm add @syntara/react @syntara/tokensimport { 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.
Speak only the start and end
announce="status" for long answers people would rather read at their own pace.
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
statusRequiredstreamingcompletestoppederror
Where the response is. The app owns it; the component never guesses from the text.
textRequiredstringThe response so far, as plain text. It is what screen readers hear, so leave out markdown symbols and code.
childrenReactNodeWhat sighted users see, such as rendered markdown. Defaults to text, with its line breaks kept.
labelstringAccessible name of the article, so it can be found by article navigation.
Default
'Response'announcesentencesdefaultstatus
sentences speaks each finished sentence as it arrives; status speaks only the start and the end.
announceIntervalnumberShortest gap between two spoken updates while streaming, in ms. Sentences that finish inside it are spoken together.
Default
1000errorMessagestringShown and spoken after the error label when status is error.
startLabel / writingLabel / completeLabel / stoppedLabel / errorLabelstringEvery spoken and shown word, for translation.
Default
'Writing response' / 'Writing…' / 'Response complete' / 'Stopped' / "Couldn't finish"
ResponseText
textRequiredstringThe response so far. New words fade in from the brand text colour; a caret glows at the end while the parent streams.
ResponseSources
labelstringAccessible name of the list of sources.
Default
'Sources'
ResponseSource
indexnumberThe citation number used in the text.
hrefstringWhere 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