Typing indicator

Free · MIT

Three 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.

MarkdownOpen in v0
Open in v0

Installation

$ npx shadcn@latest add https://goodui.dev/r/typing-indicator.json

The 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

Use it for
  • 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).
Reach for something else
  • 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 needUse
In the message listvariant="bubble" with avatar
Next to a namevariant="inline"
Just the dotsvariant="dots" (the sentence stays for screen readers)
Several peoplenames={["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

PropTypeDefault
names
Who is typing.
string | string[]—
show
Mount and unmount with an animation.
booleantrue
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