GitHub

Dots

A classic blinking-dot row—perfect beside copy, in composers, and anywhere “typing” should read instantly.

Loading
import { Dots } from "@/components/loading-ui/dots";

export function DotsDemo() {

Installation

pnpm dlx shadcn@latest add @loading-ui/dots

Usage

import { Dots } from "@/components/loading-ui/dots";
<Dots />

Customization

Dots lays out aspect-square markers with grow inside a flex row, so width on the root (for example w-16) is the main lever for overall scale. Each dot blinks on a staggered delay; color comes from bg-current and inherited foreground. The Color preview uses explicit hex swatches.

Size

Widen or narrow the container—the dots distribute evenly with a percentage gap.

LoadingLoadingLoadingLoading
import { Dots } from "@/components/loading-ui/dots";

export function DotsSize() {

Color

The first row uses semantic utilities; the second uses arbitrary hex so swatches stay obvious in any theme.

LoadingLoadingLoading
import { Dots } from "@/components/loading-ui/dots";

export function DotsColor() {

Duration

Set --duration to make the blink feel snappier or calmer.

LoadingLoadingLoading
import { Dots } from "@/components/loading-ui/dots";

export function DotsDuration() {

Dot count

Pass dots when you want a longer ellipsis or a denser beat (three is the default).

LoadingLoadingLoading
import { Dots } from "@/components/loading-ui/dots";

export function DotsCount() {

Examples

These examples lean into chat, drafts, and typing metaphors—pair with honest labels so users know it is progress, not decoration.

Button

Disabled buttons plus dots communicate a short blocking action without swapping in a different icon set.

import { Button } from "@/components/ui/button";
import { Dots } from "@/components/loading-ui/dots";

Badge

Tight chips for “typing” or “AI drafting” stay scannable because the row height matches the badge line box.

LoadingTypingLoadingAI draftingLoadingLive edit
import { Badge } from "@/components/ui/badge";
import { Dots } from "@/components/loading-ui/dots";

Accordion

Use the accordion header as a live status surface while longer copy stays tucked in the panel.

Blinking dots sell the “still writing” beat without stealing focus from the accordion chrome.

import {
  Accordion,
  AccordionContent,

Input group

A textarea footer mirrors classic messenger UX: dots plus a single line of system copy.

LoadingAssistant is still typing
Esc to cancel
import {
  InputGroup,
  InputGroupAddon,

Empty

Gradient framing makes the empty state feel transitional—swap to a message list once the first typist appears.

Loading

No messages yet

When the first participant starts typing, swap this empty state for a slim row—the dots read instantly as “someone is composing.”

import { Button } from "@/components/ui/button";
import {
  Empty,