Block Ui
block-uiuiOverlay that blocks interaction during loading. Wraps content and shows a spinner + message overlay. `bind:value` toggles the blocked state with configurable overlay opacity, color, background blur, and custom icon/message snippets. Composes the spinner primitive.
Installation
$pnpm dlx shadcn-svelte@latest add https://uipkge.dev/r/svelte/block-ui.json$npx shadcn-svelte@latest add https://uipkge.dev/r/svelte/block-ui.json$yarn dlx shadcn-svelte@latest add https://uipkge.dev/r/svelte/block-ui.json$bunx shadcn-svelte@latest add https://uipkge.dev/r/svelte/block-ui.jsonManifest:
https://uipkge.dev/r/svelte/block-ui.jsonInstalls to:src/lib/components/ui/block-ui/Examples
Loading interactive previews…
Loading interactive previews…
Props
| Name | Type / Values | Default | Required |
|---|---|---|---|
blockingPrimary blocked API (React `blocking` parity). Bind it (`bind:blocking`). Wins over `value` when both are set. | boolean | — | optional |
value@deprecated Use `blocking`. Kept as an alias — both stay functional. | boolean | — | optional |
message | string | Loading... | optional |
opacity | number | 0 | optional |
overlayColor | string | — | optional |
blur | boolean | false | optional |
showSpinner | boolean | true | optional |
iconOverride the default spinner icon. | Snippet | — | optional |
messageSnippetRich message content. Wins over the `message` string when provided. | Snippet | — | optional |
refThe wrapper <div>, via `bind:ref`. | HTMLDivElement | null | — | optional |
npm dependencies
Includes
Files installed (3)
src/lib/components/ui/block-ui/BlockUi.svelte3.1 kB
<script lang="ts" module> import type { Snippet } from 'svelte' import type { HTMLAttributes } from 'svelte/elements' export interface BlockUiProps extends HTMLAttributes<HTMLDivElement> { /** Primary blocked API (React `blocking` parity). Bind it (`bind:blocking`). Wins over `value` when both are set. */ blocking?: boolean /** Blocked state. Bind it (`bind:value`) to toggle from the parent. * @deprecated Use `blocking`. Kept as an alias — both stay functional. */ value?: boolean message?: string opacity?: number overlayColor?: string blur?: boolean showSpinner?: boolean /** Override the default spinner icon. */ icon?: Snippet /** Rich message content. Wins over the `message` string when provided. */ messageSnippet?: Snippet /** The wrapper <div>, via `bind:ref`. */ ref?: HTMLDivElement | null } </script> <script lang="ts"> import { fade } from 'svelte/transition' import { cn } from '$lib/utils' import { Spinner } from '$lib/components/ui/spinner' import { blockUiVariants } from './block-ui.variants' let { class: className, blocking = $bindable<boolean | undefined>(), value = $bindable<boolean | undefined>(), message = 'Loading...', opacity = 0.6, overlayColor = '', blur = false, showSpinner = true, icon, messageSnippet, children, ref = $bindable(null), ...restProps }: BlockUiProps = $props() const blocked = $derived(blocking ?? value ?? false) const overlayStyle = $derived( `--block-ui-opacity: ${opacity}; opacity: var(--block-ui-opacity)${overlayColor ? `; background-color: ${overlayColor}` : ''}`, ) </script> <div bind:this={ref} data-uipkge="" data-slot="block-ui" data-blocked={blocked ? '' : undefined} class={cn(blockUiVariants(), className)} {...restProps} > <!-- Wrapped content — always non-interactive while blocked (not only when blur is on). --> <div class={cn('block-ui-content', blocked && 'pointer-events-none', blur && blocked && 'blur-sm transition-[filter]')} inert={blocked || undefined} aria-hidden={blocked || undefined} > {@render children?.()} </div> <!-- Blocking overlay --> {#if blocked} <div class="absolute inset-0 z-50 flex flex-col items-center justify-center gap-3" role="status" aria-live="polite" aria-busy="true" transition:fade={{ duration: 200 }} > <!-- Background layer (opacity only affects this layer) --> <div class="absolute inset-0" class:bg-background={!overlayColor} style={overlayStyle}></div> <!-- Content layer (spinner + message stay fully opaque) --> {#if icon} {@render icon()} {:else if showSpinner} <Spinner size="lg" /> {/if} <!-- Message snippet may contain block markup — keep it out of a <p>. --> {#if messageSnippet} <div class="text-foreground text-sm font-medium"> {@render messageSnippet()} </div> {:else if message} <p class="text-foreground text-sm font-medium">{message}</p> {/if} </div> {/if} </div>src/lib/components/ui/block-ui/block-ui.variants.ts0.2 kB
import type { VariantProps } from 'class-variance-authority' import { cva } from 'class-variance-authority' export const blockUiVariants = cva('relative inline-block') export type BlockUiVariants = VariantProps<typeof blockUiVariants>src/lib/components/ui/block-ui/index.ts0.1 kB
export { default as BlockUi, type BlockUiProps } from './BlockUi.svelte' export { blockUiVariants, type BlockUiVariants } from './block-ui.variants'
Raw manifest:https://uipkge.dev/r/svelte/block-ui.json