SvLoadingOverlay
A cover-a-container loading scrim: a translucent overlay with a centred spinner that sits on top of any positioned parent while its content loads or saves.
SvLoadingOverlay fills its nearest positioned ancestor (position: absolute; inset: 0) with a scrim + SvSpinner and an optional label. Drop
it inside a position: relative wrapper so the content stays visible (optionally
blurred) underneath while an async action is in flight - a save, a fetch, a
recalculation.
Related: SvSpinner · SvSkeleton · SvResult
Installation
Add it with the CLI - this drops a ready-to-edit SvLoadingOverlay starter into your app:
Prefer to see it first? npx @svgrid/ui try loading-overlay opens it in a throwaway sandbox - no project needed.
Or install the package and import it directly. SvLoadingOverlay ships free in
@svgrid/grid (dependency-free):
import { SvLoadingOverlay } from '@svgrid/grid'
Example
<script lang="ts">
import { SvLoadingOverlay } from '@svgrid/grid'
let loading = $state(false)
</script>
<div style="position: relative">
<SvLoadingOverlay visible={loading} label="Saving…" />
<!-- panel content -->
</div>
The wrapper must be positioned (relative / absolute) - the overlay pins
itself to that box with inset: 0.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
visible |
boolean |
false |
Show the overlay. Nothing renders when false. |
label |
string |
- | Text under the spinner and the overlay's accessible name. |
spinnerSize |
sm | md | lg | number |
lg |
Size passed through to the inner SvSpinner. |
blur |
boolean |
false |
Blur the content behind the scrim. |
children |
Snippet |
- | Custom overlay content in place of the default spinner + label. |
Accessibility
- The overlay is
role="status"witharia-live="polite"and anaria-label(falls back to"Loading"), so its appearance is announced without stealing focus. - It does not trap focus. If the underlying content must be non-interactive while
loading, disable those controls or set
inerton the wrapper yourself.
Over live content
The overlay covers its children rather than replacing them, so the layout does
not jump when loading ends. blur is what stops the content behind reading as
still-interactive.
<script lang="ts">
import { SvLoadingOverlay, SvGrid, SvButton, type GridColumns } from '@svgrid/grid'
type Person = { name: string; city: string }
const people: Person[] = [
{ name: 'Ada Lovelace', city: 'London' },
{ name: 'Grace Hopper', city: 'New York' },
{ name: 'Linus Torvalds', city: 'Portland' },
]
const columns: GridColumns<Person> = [
{ field: 'name', header: 'Name', width: 180 },
{ field: 'city', header: 'City', width: 140 },
]
let busy = $state(false)
function refresh() {
busy = true
setTimeout(() => (busy = false), 1200)
}
</script>
<SvButton onclick={refresh}>Refresh</SvButton>
<SvLoadingOverlay visible={busy} label="Fetching rows..." blur>
<SvGrid data={people} {columns} />
</SvLoadingOverlay>
See also
- SvSpinner - the inline indicator used inside this overlay.
- SvSkeleton - placeholder shapes for first-load content.
- SvResult - the terminal state once the async action finishes.