8
Components

Skeleton

A customizable skeleton loader component for creating loading placeholders.

Introduction

The Skeleton component is a versatile loading placeholder that provides a better user experience during data fetching or content loading. It supports custom shapes, sizes, animations, and can be combined in different ways to match your actual content’s layout.


Basic Examples

Always Show Skeleton

Customize Your Skeleton

Enabled
Current: 4px
Yes
Current: 3 lines
Yes
Yes
No
import { Skeleton } from "@/components/ui/skeleton";
 
export function CustomSkeleton() {
  return (
    <div className="border rounded-lg p-4 max-w-sm">
      
        <Skeleton 
          className="animate-pulse aspect-video w-full rounded-md" 
          style={{ backgroundColor: "undefined", borderRadius: "4px" }}
        />
      <div className="mt-3 space-y-2">
        <Skeleton 
          className="animate-pulse h-4 w-full my-2" 
          style={{ backgroundColor: "undefined", borderRadius: "4px" }}
        />
        <Skeleton 
          className="animate-pulse h-4 w-[75%] my-2" 
          style={{ backgroundColor: "undefined", borderRadius: "4px" }}
        />
        <Skeleton 
          className="animate-pulse h-4 w-[65%] my-2" 
          style={{ backgroundColor: "undefined", borderRadius: "4px" }}
        />
      </div>
    </div>
  );
}

Timed Skeleton with Content


Installation

Install the Skeleton component using:

npx axionjs-ui add skeleton

File Structure


Prop Types

PropTypeDefault
className
string
-
otherProps
React.HTMLAttributes<HTMLDivElement>
-

Common Use Cases

Card Layout

Create skeleton placeholders for a card component:

function CardSkeleton() {
  return (
    <div className="rounded-lg border p-4 space-y-4">
      {/* Image placeholder */}
      <Skeleton className="h-48 w-full rounded-md" />
      
      {/* Title placeholder */}
      <Skeleton className="h-6 w-3/4" />
      
      {/* Content placeholders */}
      <div className="space-y-2">
        <Skeleton className="h-4 w-full" />
        <Skeleton className="h-4 w-full" />
        <Skeleton className="h-4 w-2/3" />
      </div>
      
      {/* Button placeholder */}
      <Skeleton className="h-10 w-28" />
    </div>
  );
}

Table Row Loading

Create skeleton placeholders for table rows:

function TableRowsSkeleton({ rows = 5 }) {
  return (
    <>
      {Array(rows).fill(0).map((_, index) => (
        <tr key={index} className="border-b">
          <td className="p-3"><Skeleton className="h-4 w-8" /></td>
          <td className="p-3"><Skeleton className="h-4 w-32" /></td>
          <td className="p-3"><Skeleton className="h-4 w-24" /></td>
          <td className="p-3"><Skeleton className="h-4 w-16" /></td>
          <td className="p-3"><Skeleton className="h-4 w-20" /></td>
        </tr>
      ))}
    </>
  );
}

Profile Information

Create a skeleton for user profile information:

function ProfileSkeleton() {
  return (
    <div className="flex items-center space-x-4">
      {/* Avatar */}
      <Skeleton className="h-16 w-16 rounded-full" />
      
      {/* User details */}
      <div className="space-y-2">
        <Skeleton className="h-5 w-32" />
        <Skeleton className="h-4 w-24" />
      </div>
    </div>
  );
}

Custom Colored Skeletons

Customize the skeleton color to match your design:

<Skeleton 
  className="h-12 w-full bg-blue-100" 
/>
 
<Skeleton 
  className="h-12 w-full bg-opacity-20 bg-green-500" 
/>
 
<Skeleton 
  className="h-12 w-full"
  style={{ backgroundColor: 'rgba(234, 88, 12, 0.1)' }}
/>

Customization

The Skeleton component is designed to be easily customizable:

Styling with Tailwind

// Square
<Skeleton className="h-20 w-20" />
 
// Circle/Avatar
<Skeleton className="h-12 w-12 rounded-full" />
 
// Rounded Rectangle
<Skeleton className="h-8 w-32 rounded-md" />
 
// Variable Width
<Skeleton className="h-4 w-2/3" />
 
// With Shadow
<Skeleton className="h-16 w-full rounded-md shadow-md" />

Custom Animation

You can override the default pulse animation:

// No animation
<Skeleton className="h-10 w-full animate-none" />
 
// Custom animation using CSS or Tailwind
<Skeleton className="h-10 w-full animate-[shimmer_1s_ease-in-out_infinite]" />

Conditional Rendering with Loading State

Combining with a loading state in components:

function ProductCard({ product, isLoading }) {
  return isLoading ? (
    <div className="rounded-md border p-4 space-y-3">
      <Skeleton className="h-40 w-full rounded" />
      <Skeleton className="h-6 w-3/4" />
      <Skeleton className="h-4 w-1/2" />
    </div>
  ) : (
    <div className="rounded-md border p-4 space-y-3">
      <img src={product.image} alt={product.name} className="h-40 w-full object-cover rounded" />
      <h3 className="text-lg font-semibold">{product.name}</h3>
      <p className="text-muted-foreground">${product.price}</p>
    </div>
  );
}

Accessibility

When using skeletons, keep these accessibility considerations in mind:

  • Purpose: Skeletons should provide visual cues about content structure during loading
  • ARIA: For screen reader users, consider adding an aria-live region with loading status
  • Timing: If the loading time is predictable, consider showing a timer or progress bar

Example with ARIA Support

function AccessibleSkeleton({ isLoading, children }) {
  return (
    <div aria-busy={isLoading}>
      {isLoading ? (
        <div aria-hidden="true">
          <Skeleton className="h-40 w-full rounded-md" />
          <div className="space-y-2 mt-4">
            <Skeleton className="h-4 w-full" />
            <Skeleton className="h-4 w-full" />
            <Skeleton className="h-4 w-3/4" />
          </div>
        </div>
      ) : (
        children
      )}
      {isLoading && (
        <div className="sr-only" aria-live="polite">
          Content is loading, please wait.
        </div>
      )}
    </div>
  );
}

Best Practices

For the most effective skeleton loading experience:

  1. Match Content Structure: Design skeletons to match the actual content’s layout and proportions
  2. Optimize Performance: Skeletons should be lightweight and not add rendering overhead
  3. Consistent Design: Maintain consistent styling between skeletons and actual content
  4. Sensible Timing: Only show skeletons for loads that take longer than ~300ms
  5. Avoid Layout Shifts: Ensure skeleton dimensions closely match the expected content dimensions

Conclusion

The Skeleton component is a lightweight yet powerful tool for creating loading state placeholders in your UI. With its simple implementation and high customizability, you can create effective loading experiences that reduce perceived wait times and improve user satisfaction.