Radial Dots Spinner
shadcn-extras/radial-dots-spinnerFreeComponent
Animated dotted spinner (SVG). Customizable spokes, rings, size and speed.
Install it
npx shadcn@latest add https://raw.githubusercontent.com/NayanDevLab/shadcn-extras/dev/public/c/radial-dots-spinner.jsonSource
1'use client';23import * as React from 'react';4import { cn } from '@/lib/utils';56export type RadialDotsSpinnerProps = {7 /** Overall square size (px) */8 size?: number;9 /** Number of radial spokes */10 spokes?: number;11 /** Dots per spoke (excluding center rings) */12 dotsPerSpoke?: number;13 /** Inner radius where spokes start (px) */14 innerRadius?: number;15 /** Outer radius (px). Default: size/2 - 6 */16 outerRadius?: number;17 /** Dot radius across spokes. Either fixed number or { inner, outer } to taper. */18 dotRadius?: number | { inner: number; outer: number };19 /** How many dotted rings around the center (0–3 works well) */20 centerRings?: number;21 /** Radius of the first ring (px) */22 centerRingRadius?: number;23 /** Gap between center rings (px) */24 centerRingGap?: number;25 /** Dots on each center ring */26 centerRingDots?: number;27 /** Seconds per full rotation (set 0 or falsey to disable spin) */28 speed?: number;29 /** Extra classes (use to set color: text-white, text-zinc-900, etc.) */30 className?: string;31 /** Extra classes applied to each dot (e.g. drop-shadow) */32 dotClassName?: string;33 /** Accessible label */34 label?: string;35};3637function lerp(a: number, b: number, t: number) {38 return a + (b - a) * t;39}4041export function RadialDotsSpinner({42 size = 160,43 spokes = 12,44 dotsPerSpoke = 10,45 innerRadius = 14,46 outerRadius,47 dotRadius = { inner: 2, outer: 3.5 },48 centerRings = 2,49 centerRingRadius = 10,50 centerRingGap = 6,51 centerRingDots = 16,52 speed = 1.6,53 className,54 dotClassName,55 label = 'Loading…',56}: RadialDotsSpinnerProps) {57 const w = size;58 const h = size;59 const cx = w / 2;60 const cy = h / 2;61 const R = outerRadius ?? Math.floor(size / 2) - 6;62 const step = dotsPerSpoke > 1 ? (R - innerRadius) / (dotsPerSpoke - 1) : 0;6364 const getDotR = (idx: number) => {65 if (typeof dotRadius === 'number') return dotRadius;66 const t = dotsPerSpoke <= 1 ? 0 : idx / (dotsPerSpoke - 1);67 return lerp(dotRadius.inner, dotRadius.outer, t);68 };6970 // build center rings (array of arrays of points)71 const rings = Array.from({ length: Math.max(0, centerRings) }, (_, r) => {72 const radius = centerRingRadius + r * centerRingGap;73 return Array.from({ length: centerRingDots }, (_, i) => {74 const a = (i / centerRingDots) * Math.PI * 2;75 return {76 x: cx + Math.cos(a) * radius,77 y: cy + Math.sin(a) * radius,78 };79 });80 });8182// … truncated
Files it writes
More from shadcn-extras
All 33 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Animated Image Gridanimated-image-grid | shadcn-extras | Components | Free | no deps · 3 files | |
| Blog Card Fourblog-card-four | shadcn-extras | Components | Free | 1 dep | |
| Blog Card Oneblog-card-one | shadcn-extras | Components | Free | no deps | |
| Blog Card Threeblog-card-three | shadcn-extras | Components | Free | 1 dep | |
| Blog Card Twoblog-card-two | shadcn-extras | Components | Free | 1 dep | |
| Bulb Iconbulb-icon | shadcn-extras | Components | Free | 2 deps | |
| Chevron Stepschevron-steps | shadcn-extras | Components | Free | no deps | |
| Circular Gallerycircular-gallery | shadcn-extras | Components | Free | no deps · 3 files |
