Feedback

LoadingOverlay

Covers its content with a spinner and a message while something is busy, keeping the content in place but out of reach.

#feedback#loading#status#overlay#no-js

Demo

Preview
Saved 0 times.
Loading invoices
A chart that is on its way
Loading the chart

Get it

It needs theme.qwe, as every component does; or take the whole kit, quillo-ui.qwe. Each component brings its own styles to the pages that show it.

$ curl -O https://quillolang.org/components/ui/theme.qwe$ curl -O https://quillolang.org/components/ui/loading_overlay.qwe
main.qwe
import ui/theme.qwe use theme_cssuse ui/loading_overlay.qweroute GET / = <html><head><style>{theme_css}</style></head><body class="ui-root">...</body></html>

Example

The code of the preview above.

demos/loading_overlay.qwe
component LoadingOverlayDemoLive() {    state busy = false    state saved = 0    <div.demo-stack>        <LoadingOverlay id="loading-overlay-demo-form" busy={busy} label="Saving your changes">            <div.demo-stack style="padding: 16px; border: 1px solid var(--ui-border); border-radius: var(--ui-radius)">                <TextField name="title" label="Title" value="Quarterly report"/>                <div.demo-row>                    <Button id="loading-overlay-demo-save" on_click={() => { busy = true }}>Save</Button>                    <Button variant="outline">Cancel</Button>                </div>            </div>        </LoadingOverlay>        <div.demo-row>            <Button id="loading-overlay-demo-done" variant="outline" size="sm" disabled={!busy}                    on_click={() => { busy = false; saved += 1 }}>Pretend it saved</Button>            <span.demo-note>Saved {saved} {saved == 1 ? "time" : "times"}.</span>        </div>    </div>}view LoadingOverlayDemo() =    <div.demo-stack>        <LoadingOverlayDemoLive/>        <div.demo-row>            <LoadingOverlay id="loading-overlay-demo-empty" label="Loading invoices" min_height="140px" class="demo-wide"/>        </div>        <LoadingOverlay id="loading-overlay-demo-quiet" show_label={false} blur={false} label="Loading the chart">            <div style="height: 100px; display: grid; place-items: center; border: 1px dashed var(--ui-border); border-radius: var(--ui-radius)">                A chart that is on its way            </div>        </LoadingOverlay>    </div>

Source

ui/loading_overlay.qwe
// LoadingOverlay: covers what it wraps with a spinner and a message while// something is busy, so the content stays in place (and keeps its size) but// cannot be used until it is back.////   <LoadingOverlay busy={saving} label="Saving your changes">//       <form>...</form>//   </LoadingOverlay>//   <LoadingOverlay busy={true} show_label={false} min_height="200px"/>//// busy: covers the content while true (true by default, for a box that is loading// from the start). label: what is happening ("Loading"), shown under the spinner// and read by screen readers (role="status"); show_label: false keeps it for// screen readers only. blur: softens the content underneath (true). min_height:// a CSS length, for a box with nothing in it yet. While busy the content is inert// (no clicks, no Tab stops) and the box says aria-busy. The spinner pulses instead// of turning with reduced motion.import ui/theme.qwe use ui_clslet loading_overlay_css = css`.ui-lo { position: relative; min-width: 0; }.ui-lo-content { transition: filter .2s, opacity .2s; }.ui-lo-busy > .ui-lo-content { opacity: .6; }.ui-lo-busy.ui-lo-blur > .ui-lo-content { filter: blur(2px); }.ui-lo-cover {  position: absolute; inset: 0; z-index: 5; display: grid; place-content: center; justify-items: center; gap: 10px;  padding: 16px; border-radius: inherit; background: color-mix(in srgb, var(--ui-bg) 55%, transparent);  font: 500 14px/1.4 var(--ui-font); color: var(--ui-fg); text-align: center;}.ui-lo-spin {  width: 28px; height: 28px; border-radius: 50%; border: 3px solid color-mix(in srgb, var(--ui-accent) 20%, transparent);  border-top-color: var(--ui-accent); animation: ui-lo-turn .75s linear infinite;}@keyframes ui-lo-turn { to { transform: rotate(360deg); } }@keyframes ui-lo-pulse { 50% { opacity: .35; } }@media (prefers-reduced-motion: reduce) {  .ui-lo-spin { animation: ui-lo-pulse 2s ease-in-out infinite; border-color: var(--ui-accent); }  .ui-lo-content { transition: none; }}`view LoadingOverlay(busy: bool = true, label: str = "Loading", show_label: bool = true, blur: bool = true,                    min_height: str? = null, id: str? = null, class: str? = null, children) {    style global loading_overlay_css    <div class={ui_cls(["ui-lo", busy && "ui-lo-busy", blur && "ui-lo-blur", class])} id={id}         aria-busy={busy ? "true" : null} style={min_height != null ? `min-height: ${min_height}` : null}>        <div.ui-lo-content inert={busy}>{children}</div>        {busy && <div.ui-lo-cover role="status">            <span.ui-lo-spin aria-hidden="true"></span>            <span class={show_label ? "ui-lo-label" : "ui-sr"}>{label}</span>        </div>}    </div>}
Thread
55Useful? Like it, or add to its thread below.

Thread 0 posts

On LoadingOverlay: questions, tips, corrections, and code that uses it.

No posts yet. The first one opens the thread.