Skeleton
Use to show a placeholder while content is loading.
When to Use
Use Skeleton when you need to:
- Show a placeholder while content is loading asynchronously
- Preserve the layout structure during data fetching to prevent content shift
- Reduce perceived loading time by hinting at the shape of incoming content
- Build progressive UIs that reveal content incrementally
- Replace spinners when the content structure is known in advance
Default
Profile skeleton with avatar circle and two text lines.
Card
Card skeleton with image placeholder and text lines for titles or descriptions.
List
Repeating list items with avatar and two-line text placeholders.
UX & Design Guidelines
Content Fidelity
Match skeleton dimensions as closely as possible to the actual content they replace. Use the same h-* and w-* values as the final rendered elements. This ensures a smooth, shift-free transition when content loads.
Spacing & Layout
Group related skeletons with consistent spacing using space-y-2 for tight text lines and space-y-4 for distinct content blocks. Use flex and space-x-4 for horizontal layouts like avatar + text combinations.
Animation & Timing
The default animate-pulse animation provides a subtle breathing effect. Avoid showing skeletons for loads under 300ms to prevent flicker. For very long loads (over 5 seconds), consider adding a text status message alongside the skeleton.
Color & Contrast
Skeletons use bg-accent which adapts automatically to light and dark modes. The subtle contrast against bg-background communicates a placeholder without drawing excessive attention. Avoid overriding the background color unless matching a specific container.
Accessibility
Keyboard Navigation
- Tab -- Skeleton is not focusable; focus moves through interactive elements as normal
- Escape -- No action; skeleton is decorative and non-interactive
- Once content loads, standard keyboard navigation applies to the rendered elements
Screen Reader Support
- Skeleton is purely decorative and does not require its own ARIA role
- Wrap the loading region with
aria-busy="true"while loading - Use a
role="status"live region witharia-live="polite"to announce loading state - Include
sr-onlytext like "Loading content..." for screen reader users
Focus Management
When content replaces skeleton, do not force focus unless the user initiated the load (e.g., clicking a "Load more" button). For automatic loads, let the user's current focus remain undisturbed. If the loaded content contains interactive elements, ensure they appear in logical Tab order.
Reduced Motion
The animate-pulse animation respects prefers-reduced-motion. Users with motion sensitivity will see a static placeholder instead of the pulsing animation. No additional configuration is required.
ARIA Attributes
{/* Wrap loading area with aria-busy */}
<div aria-busy="true" aria-label="Loading profile">
<Skeleton className="h-12 w-12 rounded-full" />
<Skeleton className="h-4 w-[200px]" />
</div>
{/* Announce loading state with live region */}
<div role="status" aria-live="polite">
<span className="sr-only">Loading content...</span>
<Skeleton className="h-4 w-full" />
</div>
{/* Replace skeleton when content loads */}
{isLoading ? (
<div aria-busy="true">
<Skeleton className="h-4 w-[200px]" />
</div>
) : (
<p>{content}</p>
)}Related Components
Spinner
Indeterminate loading indicator for unknown content shapes or short waits.
Progress
Determinate progress bar showing completion percentage of a task.
Card
Container component often paired with skeleton placeholders during loading.
Avatar
User image with fallback, commonly represented by a circular skeleton while loading.
API Reference
The Skeleton component accepts the following props in addition to standard div attributes.
| Prop | Type | Default | Description |
|---|---|---|---|
| className | string | "" | CSS classes for sizing, shape, and custom styles. Use h-*, w-*, and rounded-* utilities. |
| children | React.ReactNode | undefined | Optional children to render inside the skeleton container. |
| ...props | React.ComponentProps<"div"> | — | All standard HTML div attributes are forwarded to the root element. |