Typing indicator
Free · MITThree dots waving in turn with an "Aiko is typing" sentence for one or several names, as a chat bubble, inline or dots only, mounting and leaving on a spring; reduced motion keeps the dots still.
Installation
$ npx shadcn@latest add https://goodui.dev/r/typing-indicator.jsonThe file lands in components/goodui/typing-indicator.tsx and is yours to edit. With the @goodui registry added, npx shadcn@latest add @goodui/typing-indicator works too.
Usage
import { TypingIndicator } from "@/components/goodui/typing-indicator"
<TypingIndicator names="Aiko" show={waitingForFirstToken} avatar={<Sparkles />} />When to use
- The gap between sending a message and the first token of the answer.
- Human chat where one or more people are typing ("Aiko and Sam are typing").
- Inline status next to a name or in a header (inline or dots variant).
- Once tokens arrive: switch to streaming-text or chat-message with streaming.
- Long waits with known steps: reasoning-block or multi-step-loader say what is happening.
| If you need | Use |
|---|---|
| In the message list | variant="bubble" with avatar |
| Next to a name | variant="inline" |
| Just the dots | variant="dots" (the sentence stays for screen readers) |
| Several people | names={["Aiko", "Sam"]} |
Examples
Count instead of names
<TypingIndicator variant="inline" names={typers} labels={{ typing: (n) => `${n.length} people are typing` }} />German
<TypingIndicator names="Aiko" labels={{ typing: (n) => `${n.join(" und ")} schreibt…` }} />API reference
| Prop | Type | Default |
|---|---|---|
| names Who is typing. | string | string[] | — |
| show Mount and unmount with an animation. | boolean | true |
| variant bubble: a chat bubble with the dots. inline: dots and the sentence on one line. dots: dots only (the sentence stays for screen readers). | "bubble" | "inline" | "dots" | "bubble" |
| size | "sm" | "md" | "lg" | "md" |
| avatar Avatar or icon shown before the bubble. | React.ReactNode | — |
| labels Text for screen readers; pass translations here. | Partial<TypingIndicatorLabels> | — |
Also accepts every <div> attribute.
Accessibility
- The root is role="status" with aria-live="polite", so showing it announces "Aiko is typing" once; the dots are aria-hidden.
- The dots variant keeps the sentence visually hidden; bubble and inline show it.
- Built-in strings go through the labels prop for translation (the sentence is a function of the names).
Motion
- Three dots rise 35% and brighten in turn on a 1.2 s loop, offset by 150 ms each (CSS keyframes).
- show mounts it with a spring from 0.92 scale and 6px below (stiffness 520, damping 30) and unmounts with a 140 ms fade.
- Reduced motion: the dots stay still at 70% opacity and the entrance is a fade.
Notes for AI
Coding agents read these rules through MCP and llms.txt, or paste this page with Copy page.
- Toggle show rather than conditionally rendering it, so the exit animation plays.
- names accepts a string or an array; with none, the sentence is "Typing".
- Place the bubble variant where the assistant's next message will appear; it uses the same 28px avatar slot as chat-message.
FAQ
Does it announce every time the names change?
Yes, the live region reads the new sentence; keep name changes infrequent.
Related
User, assistant and system messages with avatars, grouping, a hover actions row (copy, good/bad, retry, edit), markdown-ish rendering of lists, quotes and fenced code into CodeBlocks, and a blinking caret while the answer streams.
Reveals an answer token by token at a steady speed with a cursor that blinks while waiting for more, stop and resume, word or character mode, and smooth catch-up when uneven SSE chunks arrive; reduced motion shows sentence chunks.
Six CSS-only loaders (ring, dots, bars, pulse, orbit, typing) sized in px or presets and painted with currentColor.
"Thinking 8.7s" disclosure with a live tenths timer, a shimmering label while the model reasons, the current step previewed under the header and the full step list plus notes folded inside.