Components
Skeleton
Skeleton
Animated skeleton loading component with customizable shapes and multiple line support.
Installation
1
Install the packages
npm i motion clsx tailwind-merge2
Add util file
lib/util.ts
import { ClassValue, clsx } from "clsx";
import { twMerge } from "tailwind-merge";
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}
import { ClassValue, clsx } from "clsx";
import { twMerge } from "tailwind-merge";
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}
3
Copy and paste the following code into your project
skeleton.tsx
"use client";
import { cn } from "@/lib/utils";
import { motion } from "motion/react";
import React from "react";
interface SkeletonProps {
className?: string;
variant?: "default" | "circle" | "rounded";
animated?: boolean;
lines?: number;
}
const Skeleton: React.FC<SkeletonProps> = ({
className,
variant = "default",
animated = true,
lines = 1
}) => {
const variantClasses = {
default: "rounded",
circle: "rounded-full",
rounded: "rounded-lg",
};
if (animated) {
return (
<div className="w-full max-w-xs space-y-3">
{Array.from({ length: lines }).map((_, index) => (
<motion.div
key={index}
className={cn(
"h-4 bg-neutral-700",
variantClasses[variant],
className
)}
initial={{ opacity: 0.5 }}
animate={{
opacity: [0.5, 1, 0.5],
scaleX: [1, 1.02, 1]
}}
transition={{
duration: 1.5,
repeat: Infinity,
delay: index * 0.1,
ease: "easeInOut"
}}
/>
))}
</div>
);
}
return (
<div className="w-full max-w-xs space-y-3">
{Array.from({ length: lines }).map((_, index) => (
<div
key={index}
className={cn(
"h-4 bg-neutral-700",
variantClasses[variant],
className
)}
/>
))}
</div>
);
};
export default Skeleton;"use client";
import { cn } from "@/lib/utils";
import { motion } from "motion/react";
import React from "react";
interface SkeletonProps {
className?: string;
variant?: "default" | "circle" | "rounded";
animated?: boolean;
lines?: number;
}
const Skeleton: React.FC<SkeletonProps> = ({
className,
variant = "default",
animated = true,
lines = 1
}) => {
const variantClasses = {
default: "rounded",
circle: "rounded-full",
rounded: "rounded-lg",
};
if (animated) {
return (
<div className="w-full max-w-xs space-y-3">
{Array.from({ length: lines }).map((_, index) => (
<motion.div
key={index}
className={cn(
"h-4 bg-neutral-700",
variantClasses[variant],
className
)}
initial={{ opacity: 0.5 }}
animate={{
opacity: [0.5, 1, 0.5],
scaleX: [1, 1.02, 1]
}}
transition={{
duration: 1.5,
repeat: Infinity,
delay: index * 0.1,
ease: "easeInOut"
}}
/>
))}
</div>
);
}
return (
<div className="w-full max-w-xs space-y-3">
{Array.from({ length: lines }).map((_, index) => (
<div
key={index}
className={cn(
"h-4 bg-neutral-700",
variantClasses[variant],
className
)}
/>
))}
</div>
);
};
export default Skeleton;4
Update the import paths to match your project setup
Props
| Prop | Type | Default | Description |
|---|---|---|---|
| className | string | undefined | Additional CSS classes for custom styling. |
| variant | string | default | Skeleton shape variant (default, circle, rounded). |
| animated | boolean | true | Enable shimmer animation effect. |
| lines | number | 1 | Number of skeleton lines to display. |