Installation
Usage
"use client"
import * as React from "react"
import { StreamingAnswer } from "@/components/streaming-answer"
const REPLY = "All set. Your table for **4** is held at **Toscano** on Friday at 8 pm.\n\n- Window table in the quiet section\n- Invite sent to the team"
// Stand-in for your model stream: append each chunk to `text` as it arrives.
export function Answer() {
const [text, setText] = React.useState("")
const [streaming, setStreaming] = React.useState(true)
React.useEffect(() => {
const chunks = REPLY.match(/\S+\s*/g) ?? []
let i = 0
const timer = setInterval(() => {
i += 3
setText(chunks.slice(0, i).join(""))
if (i >= chunks.length) {
clearInterval(timer)
setStreaming(false)
}
}, 120)
return () => clearInterval(timer)
}, [])
return (
<StreamingAnswer
text={text}
streaming={streaming}
actions={<button type="button" onClick={() => navigator.clipboard.writeText(text)}>Copy</button>}
/>
)
}Props
| Prop | Type | Default | Description |
|---|---|---|---|
| text | string | — | Everything the model has sent so far; grow it as tokens arrive. Paragraphs (blank lines), - lists, **bold** and `code`. |
| streaming | boolean | false | More is coming. Before the first word, a Thinking shimmer shows. |
| thinkingLabel | string | "Thinking" | The label before the first word. |
| pace | number | 30 | Steady reveal pace in words per second; it speeds up when it falls behind. |
| actions | ReactNode | — | Shown once the answer is complete: copy, regenerate, feedback. |
| onDone | () => void | — | Called once the last word is on screen and streaming has stopped. |
| ...props | HTMLAttributes<HTMLDivElement> | — | Any div attribute. |
Accessibility
- Screen readers hear whole sentences as they complete, through a polite live region, not every word.
- aria-busy is true while the answer is still arriving.
- With prefers-reduced-motion words appear without the fade, and an answer that is already complete shows at once.
Changelog
- v1.0.0Latest
First release.