Stream Response
StreamdownStreaming markdown with a block caret, inline citations and a source strip. Stop and regenerate built in.
Install
$ npx shadcn@latest add https://spotcheckui.com/r/stream-response.jsonAlso installs streamdown.
Usage
"use client"
import { StreamResponse } from "@/components/spotcheck/stream-response"
import { useStream } from "@/hooks/use-stream"
export function Answer() {
const { text, sources, status, error, start, stop, regenerate } = useStream("/api/chat")
return (
<StreamResponse
text={text}
sources={sources}
status={status}
error={error}
onStop={stop}
onRegenerate={() => regenerate()}
/>
)
}useStream reads the AI SDK's UI message stream with no ai package on the client. Return createUIMessageStreamResponse or toUIMessageStreamResponse from your route and it works. Anything else is read as plain SSE, where each data: line is more text. It also returns reset, which cancels the stream and clears it.
Use SavedResponse to show a finished reply again, with the same formatting and sources.
Write [1] in the text to cite the first source. Screen readers hear one finished sentence at a time, not every token.
Props
- text * Required
stringDefault —The text so far. Markdown is rendered as it arrives, and [1] becomes a citation. - sources
StreamSource[]Default [] - status * Required
StreamStatusDefault — - onStop
() => voidDefault —Shows a Stop button while streaming. - onRegenerate
() => voidDefault —Shows a Regenerate button once it's finished. - error
string | nullDefault —Shown if the stream fails. - className
stringDefault —
Keyboard
| Tab | Reach citations, sources and buttons |
|---|
Reduced motion
The caret stays still. Text still arrives as it streams.