Elements

05 / 37 · Reasoning

Typing indicator

The classic three dots, tuned to read as presence rather than noise.

Installation

npx shadcn@latest add "@assistant-ui/elements-typing-indicator"

Usage

import { TypingIndicator } from "@/components/elements/typing-indicator";

<TypingIndicator />

Props

variant"bubble" | "bare"bubble wraps the dots in a pill; bare renders only the three dots.
classNamestringExtra classes merged onto the root.

Source

typing-indicator.tsx
"use client";

import { cn } from "@/lib/utils";
import { paper } from "./surfaces";

const DOT_DELAYS = ["-0.32s", "-0.16s", "0s"];

export function TypingIndicator({
  variant = "bubble",
  className,
}: {
  variant?: "bubble" | "bare";
  className?: string;
}) {
  const dots = (
    <div
      role="status"
      aria-label="Assistant is typing"
      className={cn("flex gap-1", variant === "bare" && className)}
    >
      {DOT_DELAYS.map((delay) => (
        <span
          key={delay}
          aria-hidden
          className="bg-foreground/40 size-1.5 animate-bounce rounded-full motion-reduce:animate-none"
          style={{ animationDelay: delay, animationDuration: "1.1s" }}
        />
      ))}
    </div>
  );

  if (variant === "bare") {
    return dots;
  }

  return (
    <div className={cn(paper, "w-fit rounded-full px-4 py-3.5", className)}>
      {dots}
    </div>
  );
}