Feedback and status

Classic Loader

A twelve-bar radial spinner animated with CSS only.

⠋

Install

npx shadcn@latest add https://4af.selfsimilar.dev/r/classic-loader.json

Usage

import { ClassicLoader } from "@/components/ui/classic-loader";

<ClassicLoader size="md" speed={1} label="Loading results" />

API

Main export: ClassicLoader

PropDefaultDescription
size"md""sm" (16px), "md" (20px), or "lg" (32px). Override dimensions with className, such as size-12.
speed1Playback multiplier: 1 is normal, 2 is twice as fast, and 0.5 is half speed. Non-positive or non-finite values fall back to normal speed.
label—Optional accessible status name. Without a label the spinner is decorative and hidden from assistive technology.
asChildfalseRender onto a single empty child element, such as <div />, instead of the default <span>. The loader supplies its contents.

Ordinary span props, className, style, and a forwarded element ref are supported. The root exposes data-slot="classic-loader", data-variant="classic", data-size, data-loading="true", and data-state="loading".

Color and accessibility

The bars inherit currentColor. Use semantic utilities such as text-muted-foreground or text-ring; there is no separate color prop. Provide label when the spinner itself should announce a busy status. Omit it when surrounding text or a live region already communicates that status, and set aria-busy on the content being loaded where appropriate.

Motion and installation

Only opacity animates, on a 1.2s cycle. Staggered negative delays show the full trail from the first frame. The loop keeps its duration under reduced motion rather than collapsing into a strobe.

It needs no animation or primitive package. The CLI installs the theme keyframe and the utilities it uses.

Source

Adapted from Jakub Krehel's loading.dev Classic spinner. The geometry and linear fading trail come from upstream source. The upstream MIT copyright and permission notice are retained in the portable source file so they accompany every installed copy.