Skip to main content

Loading States

A comprehensive guide to skeleton components, loading patterns, and best practices for creating smooth loading experiences

Loading States

Create smooth, engaging loading experiences with our skeleton components. Each component follows consistent patterns, uses glass morphism effects, and includes built-in accessibility features for modern loading placeholders.

Available Components

Core Components

  • Skeleton - Basic skeleton shapes and variants for all content types
  • SkeletonText - Multi-line text blocks with natural line width variation
  • SkeletonCard - Pre-composed card skeletons for structured content

Layout Components

  • SkeletonImage - Image and media placeholders with aspect ratio support
  • SkeletonList - List and grid layouts with repeating skeleton items

Design Principles

1. Glass Morphism Effects

All skeleton components use subtle glass morphism with backdrop blur for a sophisticated, modern appearance that integrates seamlessly with the design system:

/* Skeleton base styling */
background: color-mix(in oklch, var(--surface) 92%, var(--neutral-500));
backdrop-filter: blur(8px);
border: 1px solid color-mix(in oklch, var(--surface) 85%, var(--neutral-400));

2. Animation Consistency

Three animation types available across all skeleton components:

  • Shimmer - Wave-like effect for active loading states
  • Pulse - Gentle opacity animation for subtle loading
  • None - Static for mockups or reduced motion preferences

3. Accessibility First

Every skeleton component includes:

  • role="status" and aria-live="polite" for screen reader announcements
  • Hidden “Loading…” text for assistive technology
  • Respects prefers-reduced-motion media query
  • Proper semantic structure maintained

Loading Patterns

Progressive Loading

Show skeletons for slow content while displaying fast content immediately:

<script>
  import Skeleton from '$lib/shared/components/loading/Skeleton.svelte';
  import SkeletonText from '$lib/shared/components/loading/SkeletonText.svelte';

  let userLoaded = $state(false);
  let contentLoaded = $state(false);

  // Fast-loading user data
  onMount(async () => {
    const user = await fetchUser(); // Fast: 100ms
    userLoaded = true;
  });

  // Slow-loading content
  onMount(async () => {
    const content = await fetchContent(); // Slow: 2s
    contentLoaded = true;
  });
</script>

<article class="post">
  <div class="author">
    {#if userLoaded}
      <img src={user.avatar} alt={user.name} />
      <span>{user.name}</span>
    {:else}
      <Skeleton variant="avatar" size="sm" />
      <Skeleton variant="text" width="120px" />
    {/if}
  </div>

  <div class="content">
    {#if contentLoaded}
      <h2>{post.title}</h2>
      <p>{post.excerpt}</p>
    {:else}
      <Skeleton variant="heading" />
      <SkeletonText lines={3} />
    {/if}
  </div>
</article>

Structured Loading

Match skeleton structure to actual content layout:

<!-- Article card skeleton -->
<div class="article-card">
  <Skeleton variant="image" />
  <div class="content">
    <Skeleton variant="heading" />
    <SkeletonText lines={2} lastLineWidth="60%" />
    <div class="meta">
      <Skeleton variant="avatar" size="sm" />
      <div>
        <Skeleton variant="text" width="100px" />
        <Skeleton variant="text" width="80px" />
      </div>
    </div>
  </div>
</div>

List Loading

Use repeating patterns for consistent list experiences:

<!-- Product list skeleton -->
<div class="product-grid">
  {#each Array(6) as _, i}
    <div class="product-card">
      <Skeleton variant="image" />
      <Skeleton variant="title" />
      <SkeletonText lines={2} />
      <Skeleton variant="button" />
    </div>
  {/each}
</div>

Animation Guidelines

Performance Optimization

Skeleton animations are optimized for performance:

  • Uses transform and opacity for GPU acceleration
  • Respects prefers-reduced-motion automatically
  • Consistent 1.5s duration across all animations
  • Minimal impact on layout reflow

Animation Selection

Choose animations based on context:

<!-- Active loading - use shimmer -->
<Skeleton variant="text" animation="shimmer" />

<!-- Subtle/background loading - use pulse -->
<Skeleton variant="text" animation="pulse" />

<!-- Static mockups - no animation -->
<Skeleton variant="text" animation="none" />

Layout Integration

Spacing Consistency

Use design system spacing tokens for skeleton layouts:

.skeleton-layout {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  padding: var(--space-6);
}

.skeleton-meta {
  display: flex;
  align-items: center;
  gap: var(--space-3);
}

Responsive Behavior

Skeletons adapt to their containers naturally:

<!-- Responsive grid -->
<div class="responsive-grid">
  {#each Array(8) as _, i}
    <SkeletonCard />
  {/each}
</div>

<style>
.responsive-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: var(--space-4);
}
</style>

Dark Mode Support

All skeleton components automatically adjust for dark mode:

/* Automatic dark mode adjustments */
:global(.dark) .skeleton-base {
  background: color-mix(in oklch, var(--surface) 96%, var(--neutral-600));
  border-color: color-mix(in oklch, var(--surface) 90%, var(--neutral-500));
}

Best Practices

1. Match Content Structure

Ensure skeleton dimensions match actual content:

  • Use same aspect ratios for images
  • Match text line heights and spacing
  • Replicate card layouts exactly
  • Mirror navigation structures

2. Timing Considerations

Optimize loading timing:

  • Show skeletons immediately (no delay)
  • Maintain for minimum 300ms (avoid flashing)
  • Fade transition between skeleton and content
  • Handle race conditions gracefully

3. Progressive Disclosure

Load content intelligently:

  • Prioritize above-the-fold content
  • Show critical information first
  • Use skeleton for secondary content
  • Implement infinite scroll with skeletons

4. Error States

Handle loading failures:

  • Replace skeleton with error message
  • Provide retry mechanisms
  • Use different styling for error states
  • Maintain accessibility during errors

Performance Tips

  1. Reuse Components - Create skeleton variants for common layouts
  2. Minimize Animations - Use static skeletons for long lists
  3. Smart Loading - Only show skeletons for slow operations
  4. Cache Strategies - Combine skeletons with data caching
  5. Batch Updates - Group skeleton-to-content transitions

Accessibility Checklist

Screen Reader Support

  • ✓ Skeleton announces “Loading…” status
  • ✓ Content replacement announced automatically
  • ✓ Loading progress communicated clearly
  • ✓ Error states properly announced

Visual Indicators

  • ✓ Sufficient contrast in light and dark modes
  • ✓ Motion respects user preferences
  • ✓ Clear loading state differentiation
  • ✓ Consistent timing across components

Keyboard Navigation

  • ✓ Focus management during loading
  • ✓ Skip links work during skeleton states
  • ✓ Tab order maintained through transitions
  • ✓ Interactive elements properly disabled