UI · components/ui/skeleton.tsx
Skeleton
Theme-aware pulsing placeholder.
34 linesGitHub ↗
Install with the shadcn CLI
First time with the kit? Read the install guide
About
Skeleton — a pulsing placeholder block.
`bg-primary/10` rather than a fixed grey: it derives from the theme, so it works in light AND dark without a second class.
THE RULE THAT MATTERS: a skeleton must mirror the real layout of the page it stands in for — same number of blocks, same rough sizes, same grid. A generic centered spinner makes the page appear to jump when content lands; a matching skeleton makes it appear to resolve.
Usage
// good — mirrors a 2-column card grid
<div className="grid gap-5 sm:grid-cols-2">
{Array.from({ length: 4 }).map((_, i) => (
<Skeleton key={i} className="h-48 rounded-xl" />
))}
</div>
Source
components/ui/skeleton.tsx · 34 lines
import { cn } from "@/lib/utils";
/**
* Skeleton — a pulsing placeholder block.
*
* `bg-primary/10` rather than a fixed grey: it derives from the theme, so it
* works in light AND dark without a second class.
*
* THE RULE THAT MATTERS: a skeleton must mirror the real layout of the page
* it stands in for — same number of blocks, same rough sizes, same grid.
* A generic centered spinner makes the page appear to jump when content
* lands; a matching skeleton makes it appear to resolve.
*
* // good — mirrors a 2-column card grid
* <div className="grid gap-5 sm:grid-cols-2">
* {Array.from({ length: 4 }).map((_, i) => (
* <Skeleton key={i} className="h-48 rounded-xl" />
* ))}
* </div>
*/
function Skeleton({
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) {
return (
<div
className={cn("animate-pulse rounded-md bg-primary/10", className)}
{...props}
/>
);
}
export { Skeleton };