Busy
REDZ.ui.busy(element, promise) marks a button or a region busy until the promise settles: a button shows a spinner and ignores clicks, a region turns inert under an overlay.
Examples
A region - a card, its body, a dialog's or a drawer's body, any region - keeps its old content under a dimmed overlay while the new comes. The overlay shows only after 400 ms, so a quick answer does not flash; once shown it stays at least 400 ms. A focus the region dropped comes back to the same element, to the element with its id in the new content, or to the region.
Bookings this week
128
bookings, 312,400 THB
<section class="card" id="busy-region-card" aria-labelledby="busy-region-title">
<div class="card-header"><h2 id="busy-region-title">Bookings this week</h2><button class="btn btn-sm ms-auto" type="button" data-docs-run="busy-region" aria-controls="busy-region-card"><i class="bi bi-arrow-repeat" aria-hidden="true"></i>Reload for 2 seconds</button></div>
<div class="card-body vstack gap-8">
<p class="fs-24 fw-600 tabular-nums">128</p>
<p class="text-muted">bookings, 312,400 THB</p>
</div>
</section>await REDZ.ui.busy(card, fetch(url).then((answer) => answer.text()).then((html) => { body.innerHTML = html; }));
A button
The button keeps its focus, ignores clicks until the promise settles and shows a spinner: in place of its leading icon, or over its words when it has none - then it keeps its size too. data-busy on the button gives the words it shows while it waits, said politely once the wait passes 400 ms; set it again before each call when the wait has steps.
<button class="btn btn-primary" type="button" data-docs-run="busy-button">Save for 2 seconds</button>
<button class="btn btn-primary" type="button" data-busy="Signing in…" data-docs-run="busy-button"><i class="bi bi-box-arrow-in-right" aria-hidden="true"></i>Sign in for 2 seconds</button>A button that starts a cooldown while it waits - "Send the code again" with data-cooldown set as the code goes - stays disabled until the count ends: the cooldown holds aria-disabled while it counts, busy() leaves it alone, and the state from before both comes back when the last of them ends.
States
What busy() sets, written by hand - the overlay appears 400 ms after the page draws it.
| element | rest | aria-busy |
|---|---|---|
| card | 128 bookings |
128 bookings |
| btn |
Accessibility
- Screen readers mostly ignore
aria-busy, and on a live region it breaks the region in some of them: here it is a styling hook, andbusy()refuses a live region in the console. - The region is
inertwhile busy: no focus, no clicks, out of the accessibility tree. When the overlay shows, one polite message says so - the page's textbusy, “Loading…”. - For a first load, where there is nothing to cover yet, use placeholders.
Tokens
From css/components/busy.css, which declares no custom property of its own.
It reads the theme's --redz-bg, --redz-primary.