Placeholder loading component that mimics content shape
Tags: component feedback loading
Skeleton components show a placeholder preview of content before it loads, reducing perceived loading time.
Import
<script>
import { Skeleton } from '@classic-homes/theme-svelte';
</script>Basic Usage
<Skeleton class="h-4 w-full" />Props
| Prop | Type | Default | Description |
|---|---|---|---|
variant |
'default' | 'text' | 'avatar' | 'card' | 'button' | 'title' |
'default' |
Predefined shape variant |
animation |
'pulse' | 'shimmer' | 'none' |
'pulse' |
Animation style |
class |
string |
- | Additional CSS classes |
Variants
Default
Custom sizing with classes:
<Skeleton class="h-4 w-full" />
<Skeleton class="h-8 w-64" />Text
Single line of text:
<Skeleton variant="text" /> <!-- h-4 w-full -->Title
Larger heading text:
<Skeleton variant="title" /> <!-- h-6 w-3/4 -->Avatar
Circular avatar placeholder:
<Skeleton variant="avatar" /> <!-- h-12 w-12 rounded-full -->Card
Card-sized placeholder:
<Skeleton variant="card" /> <!-- h-32 w-full -->Button
Button-sized placeholder:
<Skeleton variant="button" /> <!-- h-10 w-24 -->Custom Sizing
Use Tailwind classes for custom dimensions:
<!-- Custom width -->
<Skeleton class="h-4 w-32" />
<Skeleton class="h-4 w-1/2" />
<!-- Custom height -->
<Skeleton class="h-20 w-full" />
<!-- Custom shape -->
<Skeleton class="h-16 w-16 rounded-lg" />Examples
Text Content Loading
<div class="space-y-2">
<Skeleton variant="title" />
<Skeleton variant="text" />
<Skeleton variant="text" />
<Skeleton class="h-4 w-2/3" />
</div>User Card Loading
<div class="flex items-center gap-4">
<Skeleton variant="avatar" />
<div class="space-y-2 flex-1">
<Skeleton class="h-4 w-32" />
<Skeleton class="h-3 w-24" />
</div>
</div>Card Loading
<Card>
<CardHeader>
<Skeleton variant="title" />
<Skeleton variant="text" class="mt-2" />
</CardHeader>
<CardContent>
<Skeleton variant="card" />
</CardContent>
<CardFooter>
<Skeleton variant="button" />
</CardFooter>
</Card>Table Row Loading
<tr>
<td><Skeleton class="h-4 w-8" /></td>
<td><Skeleton class="h-4 w-32" /></td>
<td><Skeleton class="h-4 w-48" /></td>
<td><Skeleton class="h-4 w-24" /></td>
</tr>Grid Loading
<div class="grid grid-cols-3 gap-4">
{#each Array(6) as _}
<div class="space-y-2">
<Skeleton class="h-32 w-full" />
<Skeleton variant="title" />
<Skeleton variant="text" />
</div>
{/each}
</div>Profile Page Loading
<div class="space-y-6">
<!-- Header -->
<div class="flex items-center gap-6">
<Skeleton class="h-24 w-24 rounded-full" />
<div class="space-y-2">
<Skeleton class="h-8 w-48" />
<Skeleton class="h-4 w-32" />
</div>
</div>
<!-- Stats -->
<div class="grid grid-cols-3 gap-4">
{#each Array(3) as _}
<Skeleton class="h-20" />
{/each}
</div>
<!-- Content -->
<div class="space-y-2">
<Skeleton variant="text" />
<Skeleton variant="text" />
<Skeleton class="h-4 w-3/4" />
</div>
</div>Conditional Loading
{#if loading}
<div class="space-y-2">
<Skeleton variant="title" />
<Skeleton variant="text" />
<Skeleton variant="text" />
</div>
{:else}
<div>
<h2>{title}</h2>
<p>{content}</p>
</div>
{/if}Image Loading
<div class="relative">
{#if imageLoading}
<Skeleton class="h-64 w-full" />
{/if}
<img
src={imageUrl}
onload={() => (imageLoading = false)}
class={imageLoading ? 'invisible absolute' : ''}
/>
</div>Animation
Control the animation style with the animation prop:
Pulse (default)
Fades opacity in and out. Subtle and widely used:
<Skeleton animation="pulse" class="h-4 w-full" />Shimmer
A sweeping gradient highlight that moves across the element. More visually distinctive:
<Skeleton animation="shimmer" class="h-4 w-full" />Great for card or media loading states where you want a polished feel:
<div class="border rounded-lg p-4 space-y-3">
<Skeleton animation="shimmer" class="h-32 w-full rounded" />
<Skeleton animation="shimmer" class="h-5 w-3/4" />
<Skeleton animation="shimmer" class="h-4 w-full" />
</div>None
Static placeholder with no animation:
<Skeleton animation="none" class="h-4 w-full" />Useful for print stylesheets or reduced-motion contexts where you want full control.
All animations are CSS-based, performant, and respect prefers-reduced-motion.
Accessibility
- Skeletons are decorative and don't need ARIA labels
- Use
aria-busy="true"on the container for screen readers - Provide loading state context when needed
<div aria-busy={loading} aria-live="polite">
{#if loading}
<Skeleton variant="text" />
{:else}
<p>{content}</p>
{/if}
</div>Related Components
- Spinner - For indeterminate loading
- ProgressBar - Determinate/indeterminate progress indicator
- LoadingOverlay - Overlay with skeleton variant
- LoadingSection - Section wrapper with loading state
- Card - Container for skeleton content