StreamingChat
Token-by-token chat UI with markdown rendering, abort, retry and optimistic message state.
- SSE
- Markdown
- React 19
AI-01Illustrative preview of the intended interface.
Overview
What it solves
The problem
Streaming responses look simple, but naive implementations re-render on every token, jump the reader's scroll position and leave users with no way to stop or recover.
The approach
StreamingChat renders tokens once per frame, protects the reader's scroll position and ships stop, retry and regenerate controls out of the box.
Features
Key features
- 01
Frame-batched rendering
Incoming tokens are buffered and flushed once per animation frame, so React never renders faster than the screen refreshes.
- 02
Incremental markdown
Lists, code blocks and inline formatting render as they stream, without reflowing the message.
- 03
Abort, retry, regenerate
Stop mid-answer, keep the partial text, and retry from the same point.
- 04
Scroll anchoring
Follows the stream only while the reader is at the bottom, with a jump-to-latest button otherwise.
Under the hood
How it works
- 1
Send
The message is added optimistically and a request opens with an AbortController.
- 2
Stream
Chunks are buffered and flushed on the next animation frame.
- 3
Render
Markdown is parsed incrementally; code blocks are highlighted once they close.
- 4
Settle
The final message is committed, controls return and any error offers a retry.
See it
Demo
Walkthrough video coming soon
A short screen recording will appear here.
Developer experience
Usage
Planned API — this shows the intended developer experience and may change as the component is built.
<StreamingChat
endpoint="/api/chat"
onFinish={(message) => save(message)}
suggestions={["Summarise this report", "Draft a reply"]}
/>AI Interfaces
States and interactions
Every state a real conversation passes through, and what the user sees.
| State | Behaviour |
|---|---|
| Idle | Input focused, suggestions visible. |
| Streaming | Tokens appended per frame; Stop button shown. |
| Stopped | Partial answer kept, marked as stopped, Retry offered. |
| Error | Message preserved with inline retry; typed input is never lost. |
| Offline | Sending disabled with a clear explanation. |
Roadmap
Status & stack
Build progress
- Design & API — done
- Build — in progress
- Accessibility & performance testing — not started
- Demo & write-up — not started
Tech stack
- React 19
- TypeScript
- Fetch streams
- AbortController
- Tailwind CSS
Related research
- AI Interfaces4 min read
Building a streaming chat UI that doesn't jank
Token-by-token rendering, scroll behaviour and abort handling — the patterns that keep an LLM chat feeling instant.
- Streaming
- React 19
- UX
Read the note
More in AI Interfaces
AI-02PlannedPromptPlayground
Side-by-side prompt and model comparison with parameter controls and shareable runs.
- Multi-model
- Diff view
- TypeScript
AI-03PlannedAgentTraceViewer
Timeline of tool calls, reasoning steps and token cost for debugging agent runs.
- Observability
- Timeline
- Tool use