GitHub

Dash ring

An SVG dash-stroke ring with morphing length—strong for streaming and indeterminate progress.

import { DashRing } from "@/components/loading-ui/dash-ring";

export function DashRingDemo() {

Installation

pnpm dlx shadcn@latest add @loading-ui/dash-ring

Usage

import { DashRing } from "@/components/loading-ui/dash-ring";
<DashRing />

Customization

DashRing is an SVG with a faint track and an animated dash. The motion blends rotation with changing dash length, which reads well for streaming, LLM output, and other states where percent-complete is fuzzy.

Size

Use size-* on the SVG root for inline controls, headers, and empty-state icons.

import { DashRing } from "@/components/loading-ui/dash-ring";

export function DashRingSize() {

Color

stroke="currentColor" on the circles means text and foreground utilities tint both the track and the active dash.

import { DashRing } from "@/components/loading-ui/dash-ring";

export function DashRingColor() {

Ring weight

Target the circles with a descendant selector to tune stroke width without forking the component.

import { DashRing } from "@/components/loading-ui/dash-ring";

export function DashRingRingWeight() {

Animation cadence

The dash morph and rotation timings are defined on the SVG’s <animate> elements. To change the feel, edit those dur values (and matching keyTimes) in dash-ring.tsx—they are not wired to Tailwind’s animation-duration utilities.

Examples

These examples lean into fluid, in-flight work: streaming copy, expandable diagnostics, and assistant surfaces.

Button

In buttons, the dash ring signals blending or merging work rather than a simple fetch.

import { Button } from "@/components/ui/button";
import { DashRing } from "@/components/loading-ui/dash-ring";

Alert

Use it when you want a calm, non-blocking heads-up that output quality is still converging.

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

Collapsible

Tuck verbose logs behind a collapsible while the spinner stays visible in the summary row.

stream: open
codec: utf-8
backpressure: nominal
import { ChevronsUpDownIcon } from "lucide-react";

import {

Input group

A textarea footer is a natural place to show synthesis status tied to the prompt above.

Synthesizing answer…
import {
  InputGroup,
  InputGroupAddon,