Skip to main content

LoadingSection

LoadingSection

Section-level content wrapper with loading overlay

Tags: component feedback loading section

View Demo

A container that wraps content with a loading overlay. Handles aria-busy, minimum height preservation, and overlay composition in a single component. Ideal for independently-loading dashboard panels, card content, or any section of a page.

Import​

<script>
  import { LoadingSection } from '@classic-homes/theme-svelte';
</script>
import { LoadingSection } from '@classic-homes/theme-react';

Basic Usage​

<LoadingSection loading={isLoading}>
  <div class="p-4">
    <h3>Dashboard Stats</h3>
    <p>Revenue: $45,231</p>
  </div>
</LoadingSection>

Props​

Prop Type Default Description
loading boolean false Whether loading is active
variant 'spinner' | 'skeleton' | 'logo' | 'progress' 'spinner' Indicator type
message string - Loading message
progress number - Progress value (0–100)
minHeight string '12rem' Minimum height to preserve layout
blur boolean true Backdrop blur effect
delay number 0 Delay in ms before showing
children Snippet (Svelte) / ReactNode (React) - Content being loaded
class string - Additional CSS classes

How It Works​

LoadingSection renders a <div> wrapper with:

  • position: relative to contain the overlay
  • min-height to prevent layout collapse during loading
  • aria-busy={loading} for accessibility
  • A LoadingOverlay in overlay mode when loading
<!-- Rendered structure -->
<div class="relative" style="min-height: 12rem" aria-busy="true">
  <!-- Your content (blurred behind overlay) -->
  <div>...</div>
  <!-- Overlay appears when loading -->
  <div role="status" class="absolute inset-0 ...">
    <Spinner />
  </div>
</div>

Indicator Variants​

Spinner (default)​

<LoadingSection loading variant="spinner" message="Loading...">
  <MyContent />
</LoadingSection>

Skeleton​

<LoadingSection loading variant="skeleton">
  <MyContent />
</LoadingSection>
<LoadingSection loading variant="logo">
  <MyContent />
</LoadingSection>

Progress​

<LoadingSection loading variant="progress" progress={45}>
  <MyContent />
</LoadingSection>

Examples​

Dashboard Panels​

Multiple sections loading independently:

<div class="grid grid-cols-2 gap-4">
  <LoadingSection loading={statsLoading} message="Loading stats...">
    <Card>
      <CardHeader><CardTitle>Revenue</CardTitle></CardHeader>
      <CardContent><p class="text-2xl font-bold">$45,231</p></CardContent>
    </Card>
  </LoadingSection>

  <LoadingSection loading={chartLoading}>
    <Card>
      <CardHeader><CardTitle>Chart</CardTitle></CardHeader>
      <CardContent><MyChart /></CardContent>
    </Card>
  </LoadingSection>
</div>

Data Table Loading​

<LoadingSection loading={tableLoading} variant="skeleton" minHeight="20rem">
  <DataTable {columns} data={rows} />
</LoadingSection>

Form Submission​

<LoadingSection loading={submitting} message="Saving changes..." minHeight="auto">
  <form onsubmit={handleSubmit}>
    <Input name="email" />
    <Button type="submit">Save</Button>
  </form>
</LoadingSection>

Custom Minimum Height​

Adjust minHeight to match your content:

<!-- Smaller section -->
<LoadingSection loading minHeight="6rem">
  <p>Small content area</p>
</LoadingSection>

<!-- Larger section -->
<LoadingSection loading minHeight="24rem">
  <div>Large content area</div>
</LoadingSection>

Without Blur​

<LoadingSection loading blur={false}>
  <p>Content visible without blur behind overlay</p>
</LoadingSection>

With Delay​

Prevent flash for typically-fast operations:

<LoadingSection loading={saving} delay={300} message="Saving...">
  <MyForm />
</LoadingSection>

Fetch Pattern​

<script>
  import { LoadingSection } from '@classic-homes/theme-svelte';

  let data = $state(null);
  let loading = $state(true);
  let error = $state(null);

  onMount(async () => {
    try {
      const res = await fetch('/api/data');
      data = await res.json();
    } catch (e) {
      error = e;
    } finally {
      loading = false;
    }
  });
</script>

<LoadingSection {loading}>
  {#if error}
    <Alert variant="destructive">{error.message}</Alert>
  {:else if data}
    <DataDisplay {data} />
  {/if}
</LoadingSection>

Accessibility​

  • Automatically sets aria-busy={loading} on the wrapper container
  • The internal overlay uses role="status" and aria-live="polite"
  • Content remains in the DOM while loading (just visually obscured), preserving focus management
  • Screen readers announce the loading message when the overlay appears
Tip

LoadingSection is the recommended way to show section-level loading states because it correctly manages aria-busy on the container that owns both the content and the overlay.

On this page