Sparkling Grid
ui-beats/sparkling-gridFreeComponent
The SparklingGrid component creates an animated grid of dots that ripples outward on mount and sparkles at random, ideal for dynamic, atmospheric backgrounds.
Install it
npx shadcn@latest add https://uibeats.com/r/sparkling-grid.jsonSource
1"use client";23import { useEffect, useRef } from "react";4import { motion, useReducedMotion } from "motion/react";56interface SparklingGridProps {7 /** Spacing between dots, in pixels. */8 gridSize?: number;9 /** Chance (0–1) that a given dot sparkles on each of its ticks. */10 sparkleFrequency?: number;11 className?: string;12}1314/**15 * An animated grid of dots that ripples outward on mount, then sparkles at16 * random.17 *18 * Colour comes from `currentColor`, so it inherits whatever text colour the19 * parent sets and follows the theme with no JS involved.20 */21export function SparklingGrid({22 gridSize = 30,23 sparkleFrequency = 0.03,24 className = "",25}: SparklingGridProps) {26 const containerRef = useRef<HTMLDivElement>(null);27 const prefersReducedMotion = useReducedMotion();2829 useEffect(() => {30 const container = containerRef.current;31 if (!container) return;3233 // Every timer is tracked so unmount can cancel all of them. The previous34 // version left the sparkle loop rescheduling itself forever after the35 // component was gone.36 const timers = new Set<ReturnType<typeof setTimeout>>();37 const later = (fn: () => void, ms: number) => {38 const id = setTimeout(() => {39 timers.delete(id);40 fn();41 }, ms);42 timers.add(id);43 return id;44 };4546 const build = () => {47 container.replaceChildren();4849 const { offsetWidth: width, offsetHeight: height } = container;50 if (width === 0 || height === 0) return;5152 const rows = Math.ceil(height / gridSize);53 const cols = Math.ceil(width / gridSize);54 const centerRow = rows / 2;55 const centerCol = cols / 2;56 const maxDistance = Math.hypot(centerRow, centerCol) || 1;5758 const fragment = document.createDocumentFragment();5960 for (let row = 0; row < rows; row++) {61 for (let col = 0; col < cols; col++) {62 const dot = document.createElement("span");63 dot.className =64 "absolute size-[3px] rounded-full bg-current transition-all duration-700";65 dot.style.left = `${col * gridSize}px`;66 dot.style.top = `${row * gridSize}px`;6768 if (prefersReducedMotion) {69 dot.style.opacity = "0.2";70 fragment.appendChild(dot);71 continue;72 }7374 dot.style.opacity = "0";75 dot.style.transform = "scale(0)";76 fragment.appendChild(dot);7778 // Distance from the centre drives the delay, which is what makes79// … truncated
What it pulls in
npm packages
Files it writes
More from ui-beats
All 34 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Animated Beamanimated-beam | ui-beats | Components | Free | 1 dep | |
| Animated Listanimated-list | ui-beats | Components | Free | 1 dep | |
| Border Beamborder-beam | ui-beats | Components | Free | 1 dep | |
| Bouncebounce | ui-beats | Components | Free | 1 dep | |
| Card Stackcard-stack | ui-beats | Components | Free | 1 dep | |
| Dockdock | ui-beats | Components | Free | 1 dep | |
| Fade Infade-in | ui-beats | Components | Free | 1 dep | |
| Fade In Unblurfade-in-unblur | ui-beats | Components | Free | 1 dep |
