GitHub

Bouncing dots

Elastic scale-and-opacity dots—bouncy inline feedback for queues, ingests, and playful waits.

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

export function BouncingDotsDemo() {

Installation

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

Usage

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

Customization

BouncingDots shares the same flex row recipe as Dots and Typing: percentage gap, grow markers, and bg-current (inherited foreground). Each dot eases between smaller dimmer and larger brighter keyframes. Timing uses --duration (default 1.4s); stagger delays stay fixed.

Size

Control overall width—the dots share space evenly inside the row.

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

export function BouncingDotsSize() {

Color

Arbitrary hex swatches for obvious documentation color.

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

export function BouncingDotsColor() {

Duration

Slow the bounce for calmer surfaces or speed it up for snappy microtasks.

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

export function BouncingDotsDuration() {

Dot count

Add markers when the queue feels busier or you want a wider rhythm.

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

export function BouncingDotsCount() {

Examples

Surface variety keeps the bounce from feeling repetitive: alerts for status, a bottom sheet for mobile-friendly queues, tabs for live vs history, and a tight popover for async hints.

Button

gap-2 gives the row room to expand without crowding the label.

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

Badge

Compact chips for “spring load” or retry states.

LoadingSpring loadLoadingRetry waveLoadingLive queue
import { Badge } from "@/components/ui/badge";
import { BouncingDots } from "@/components/loading-ui/bouncing-dots";

Alert

Pair with operational copy when throughput is still stretching.

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

Sheet

side="bottom" is ideal for thumb reach plus a centered bounce.

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

Tabs

Let users compare live ingest against a quieter history tab.

Loading

Ingest still stretching

Switch tabs freely—the animation loops until the stream closes.

import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { BouncingDots } from "@/components/loading-ui/bouncing-dots";

Popover

Short copy, small footprint, one accent color on the dots.

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