Primitives
Spinner
Accessible loading indicator for pending buttons, panels, and inline waits.
Composition
Pending indicator
- <Spinner />
Installation
First install and activate one skin. Core deliberately contains no visual token defaults.
The Control UI source installs this primitive from src/registry/sources/control-ui/ui/spinner.tsx.
npx shadcn@latest add https://control-ui.dev/r/spinner.jsonDependencies
Effects
src/registry/sources/control-ui/effects.cssSupportRaw code
Primary installed source
import { Loader2 } from "lucide-react";import type { ComponentProps, CSSProperties } from "react";import type { ControlSize } from "@/components/control-ui/control-variants";import type { SpinnerKnobStyle } from "@/components/control-ui/knob-contracts/spinner-knobs";import { cn } from "@/components/control-ui/lib/cn";export type SpinnerProps = Omit< ComponentProps<"span"> & { size?: ControlSize; label?: string; }, "style" | "children"> & { style?: CSSProperties & SpinnerKnobStyle };export function Spinner({ size = "sm", label = "Loading", className, ...props }: SpinnerProps) { return ( <span role="status" data-control-ui="spinner" data-control-family="spinner" data-slot="root" data-motion-essential="" className={cn("inline-flex", className)} {...props} > <Loader2 aria-hidden="true" data-control-ui="spinner" data-control-family="spinner" data-slot="indicator" data-size={size} /> <span className="sr-only">{label}</span> </span> );}Knobs
Typed custom properties the recipe paints with. Set one on the root — style, a utility class, or a skin — and every slot inherits it.
--cui-spinner-* · 2 knobsHow the cascade resolves--cui-spinner-foreground<color>var(--muted-foreground)--cui-spinner-animation-duration<time>var(--duration-loop)