Installation
npx shadcn@latest add @assistant-ui/dot-matrixThe @assistant-ui namespace resolves the Radix or Base UI flavor from your project's style through the style-aware registry entry in components.json. Without that entry, add by direct URL instead:
npx shadcn@latest add https://r.assistant-ui.com/base/dot-matrix.jsonMain Component
This adds a /components/ui/dot-matrix.tsx file to your project, which you can adjust as needed. The component has no dependencies beyond React.
Usage
import { DotMatrix } from "@/components/ui/dot-matrix";
export function RunIndicator({ isRunning }: { isRunning: boolean }) {
return <DotMatrix state={isRunning ? "loading" : "success"} />;
}Dots inherit the surrounding text color, so the matrix renders dark dots on light backgrounds and light dots on dark backgrounds without configuration. Every state is a combination of a dot pattern, a motion, and a color, and switching states cross-fades each dot into its new pattern.
States
| State | Pattern |
|---|---|
idle | Dim static grid |
loading | Randomized twinkle (default) |
thinking | Diagonal wave |
streaming | Falling rain, per-column streaks |
searching | Horizontal sweep |
syncing | Rotating sweep around the center |
connecting | Ripple expanding from the center |
waiting | Ellipsis dots blinking in sequence |
uploading | Wave rising upward |
downloading | Wave falling downward |
listening | Slow equalizer columns |
speaking | Fast equalizer columns |
recording | Red center dot breathing |
success | Green check glyph, static |
error | Red cross glyph, blinking |
warning | Amber exclamation glyph, slow blink |
info | Blue info glyph, static |
paused | Pause bars glyph, static |
stopped | Square glyph, static |
offline | Very dim static grid |
The component exports dotMatrixStates (the ordered list above) and the DotMatrixState union type, so UIs can enumerate or map states without duplicating the list. New states are added by extending the STATES record in the component source with a glyph and a per-dot blink function.
Examples
State Lifecycle
Drive the state prop from your run status; the matrix morphs between patterns instead of swapping components.
Inline With Text
At the default size-4 the matrix aligns with text like an icon, and the dots adapt to inverted surfaces through currentColor.
Sizes
The matrix is an SVG, so any size utility scales it crisply.
How It Works
The grid is a 5x5 SVG of currentColor circles. Blinking is a single CSS keyframe animation whose high/low opacity bounds come from registered per-dot CSS variables; the animation runs in every state (static states collapse the bounds) and the bounds carry a transition, which is what makes state changes cross-fade per dot. The randomized loading rhythm uses deterministic per-dot delays and durations, so server and client render identical markup and no JavaScript runs after render. With prefers-reduced-motion, the dots hold their resting opacity instead of blinking.
The root is a role="status" live region whose text content is the state name (or the label prop), so screen readers announce state changes; the SVG itself is aria-hidden.
API Reference
DotMatrix
DotMatrixPropsstate: DotMatrixState= "loading"One of the 20 built-in states listed above, controlling pattern, motion, and color.
label?: stringAccessible label announced by screen readers. Defaults to the state name.
className?: stringAdditional CSS classes. Use size utilities to scale and text color utilities to recolor.
Styling
Color follows currentColor, so className="text-blue-500" recolors the whole matrix; the outcome states (success, error, warning, info, recording, and the muted static states) set their own color which a className can override. Dots are targetable via [data-slot="dot-matrix"] and [data-slot="dot-matrix-dot"], and the current state is exposed as data-state on the root.
Related Components
- Number Roll - Animated rolling number
- Badge - Small status and metadata labels
- Voice - Voice activity visualization