Typing Indicators & Streaming Responses
Typing indicators and streaming responses solve the same problem: never make a user stare at a blank screen while the AI works. Indicators are right for waits under three seconds; streaming is the modern default everywhere else. This lesson covers both, with code.
The Three Response Patterns
Typing Indicator (Three Bouncing Dots)
Use for short waits (< 3 seconds). Shows "the AI is thinking" without committing to a response format. This is what Slack and iMessage use. Build it with three small circles using animate-bounce with staggered delays.
Streaming Text
The modern standard for AI chat. Tokens appear as they're generated, giving users something to read immediately. ChatGPT and Claude both use this. You consume a Server-Sent Events (SSE) stream and append tokens to the message.
Status Phases
For complex tasks, show distinct phases: "Searching..." then "Reading 3 documents..." then "Writing response..." This is what Perplexity and research-focused AIs use. Each phase reassures the user that progress is happening.
Implementing Streaming
Most AI APIs (OpenAI, Anthropic, Google) support streaming via Server-Sent Events. Here's the pattern:
async function streamResponse(userMessage: string, onToken: (token: string) => void) {
const response = await fetch('/api/chat', {
method: 'POST',
body: JSON.stringify({ message: userMessage }),
});
const reader = response.body?.getReader();
const decoder = new TextDecoder();
while (reader) {
const { done, value } = await reader.read();
if (done) break;
const text = decoder.decode(value);
onToken(text);
}
}In your component, create a "streaming" message and append tokens to it:
The message bubble shows streamingContent with a blinking cursor at the end.
Add a subtle blinking cursor (▊) at the end of streaming text. It signals "more is coming" and prevents users from thinking the response is done mid-sentence.