The Skeleton component provides a visual placeholder while content is loading, with support for pulse, shimmer, and gradient animations.
Installation
npx shadcn@latest add @eo-n/skeleton
Install dependencies
npm install class-variance-authority
Copy component code
Copy and paste the following code into your project at components/ui/skeleton.tsx:import * as React from "react";
import { cva, type VariantProps } from "class-variance-authority";
import { cn } from "@/lib/utils";
const skeletonVariants = cva("bg-primary/10 rounded-md", {
variants: {
variant: {
pulse: "animate-pulse",
shimmer:
"before:animate-skeleton-shimmer before:via-primary/10 dark:before:via-primary/5 relative overflow-hidden before:absolute before:inset-0 before:-translate-x-full before:bg-gradient-to-r before:from-transparent before:to-transparent",
gradient:
"bg-gradient-to-r from-primary/5 via-primary/10 to-primary/5 animate-skeleton-gradient bg-[length:400%_100%]",
},
},
defaultVariants: {
variant: "pulse",
},
});
export type SkeletonVariants = VariantProps<typeof skeletonVariants>;
interface SkeletonProps extends React.ComponentProps<"div">, SkeletonVariants {}
export function Skeleton({ className, variant, ...props }: SkeletonProps) {
return (
<div
data-slot="skeleton"
className={cn(skeletonVariants({ className, variant }))}
{...props}
/>
);
}
Add animations to globals.css
Define the shimmer and gradient keyframes in your globals.css file:@import "tailwindcss";
@theme inline {
--animate-skeleton-shimmer: skeleton-shimmer 2s infinite ease-out;
--animate-skeleton-gradient: skeleton-gradient 2s infinite ease-out;
@keyframes skeleton-shimmer {
0% {
transform: translateX(-100%);
}
100% {
transform: translateX(200%);
}
}
@keyframes skeleton-gradient {
0%,
100% {
background-position: 0% 50%;
}
50% {
background-position: 100% 50%;
}
}
}
Update imports
Update the import paths to match your project setup.
Usage
import { Skeleton } from "@/components/ui/skeleton";
<Skeleton className="h-12 w-64" />
Examples
Pulse (Default)
The default variant with a subtle pulse animation:
<Skeleton className="h-4 w-48" />
Shimmer
A shimmer effect that sweeps across the skeleton:
<Skeleton variant="shimmer" className="h-4 w-48" />
Gradient
A gradient animation that flows across the skeleton:
<Skeleton variant="gradient" className="h-4 w-48" />
Card Skeleton
<div className="space-y-3">
<Skeleton className="h-32 w-full rounded-lg" />
<div className="space-y-2">
<Skeleton className="h-4 w-3/4" />
<Skeleton className="h-4 w-1/2" />
</div>
</div>
Avatar Skeleton
<div className="flex items-center space-x-4">
<Skeleton className="size-12 rounded-full" />
<div className="space-y-2">
<Skeleton className="h-4 w-48" />
<Skeleton className="h-3 w-32" />
</div>
</div>
Table Skeleton
<div className="space-y-2">
<Skeleton className="h-10 w-full" />
<Skeleton className="h-10 w-full" />
<Skeleton className="h-10 w-full" />
<Skeleton className="h-10 w-full" />
</div>
Component API
Skeleton
variant
'pulse' | 'shimmer' | 'gradient'
The animation variant to use.
pulse - Default pulsing opacity animation
shimmer - Sweeping shimmer effect
gradient - Flowing gradient animation
Additional CSS classes to control size, shape, and other styles.
...props
React.ComponentProps<'div'>
All standard HTML div element props are supported.
Accessibility
The Skeleton component should be used for visual feedback only. Ensure you:
- Remove skeletons and replace with actual content once loaded
- Use appropriate ARIA live regions if needed for announcing content changes
- Consider adding
aria-busy="true" to parent containers while loading
Animation Performance
The shimmer and gradient variants require custom CSS animations. Make sure you’ve added the keyframe definitions to your global CSS file as shown in the installation steps.