Section-level content wrapper with loading overlay
Tags: component feedback loading section
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: relativeto contain the overlaymin-heightto prevent layout collapse during loadingaria-busy={loading}for accessibility- A LoadingOverlay in
overlaymode 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>Logo
<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"andaria-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.
Related Components
- LoadingOverlay - Lower-level overlay for custom compositions
- LoadingPage - Full-page branded loading screen
- Skeleton - Content placeholder shapes
- Spinner - Simple loading indicator