Block Ui
block-ui ui Overlay that blocks interaction during loading. Wraps content and shows a spinner + message overlay. v-model toggles the blocked state with configurable overlay opacity, color, background blur, and custom icon/message slots. Composes the spinner primitive.
Also available for React ->Installation
$ pnpm dlx shadcn-vue@latest add https://uipkge.dev/r/vue/block-ui.json $ npx shadcn-vue@latest add https://uipkge.dev/r/vue/block-ui.json $ yarn dlx shadcn-vue@latest add https://uipkge.dev/r/vue/block-ui.json $ bunx shadcn-vue@latest add https://uipkge.dev/r/vue/block-ui.json Named registry:
npx shadcn-vue@latest add @uipkge/block-ui Installs to: app/components/ui/block-ui/ Examples
Props
| Name | Type / Values | Default | Required |
|---|---|---|---|
modelValue | boolean | false | optional |
message | string | 'Loading...' | optional |
opacity | number | 0.6 | optional |
overlayColor | string | '' | optional |
blur | boolean | false | optional |
showSpinner | boolean | true | optional |
class | HTMLAttributes['class'] | — | optional |
npm dependencies
Includes
Files installed (3)
-
app/components/ui/block-ui/BlockUi.vue 2.2 kB
<script setup lang="ts"> import type { HTMLAttributes } from 'vue' import { computed, useSlots } from 'vue' import { cn } from '@/lib/utils' import { blockUiVariants } from './block-ui.variants' import { Spinner } from '@/components/ui/spinner' interface Props { modelValue?: boolean message?: string opacity?: number overlayColor?: string blur?: boolean showSpinner?: boolean class?: HTMLAttributes['class'] } const props = withDefaults(defineProps<Props>(), { modelValue: false, message: 'Loading...', opacity: 0.6, overlayColor: '', blur: false, showSpinner: true, }) const emit = defineEmits<{ 'update:modelValue': [value: boolean] }>() const slots = useSlots() const hasIconSlot = computed(() => !!slots.icon) const overlayStyle = computed(() => { const style: Record<string, string> = { opacity: String(props.opacity), } if (props.overlayColor) style.backgroundColor = props.overlayColor return style }) </script> <template> <div data-uipkge data-slot="block-ui" :data-blocked="modelValue ? '' : undefined" :class="cn(blockUiVariants(), props.class)" > <!-- Wrapped content --> <div :class="cn('block-ui-content', blur && modelValue && 'pointer-events-none blur-[2px] transition-[filter]')"> <slot /> </div> <!-- Blocking overlay --> <Transition name="block-ui-fade"> <div v-if="modelValue" class="absolute inset-0 z-50 flex flex-col items-center justify-center gap-3" role="status" aria-live="polite" aria-busy="true" > <!-- Background layer (opacity only affects this layer) --> <div class="absolute inset-0" :style="overlayStyle" :class="!overlayColor && 'bg-background'" /> <!-- Content layer (spinner + message stay fully opaque) --> <slot name="icon"> <Spinner v-if="showSpinner" size="lg" /> </slot> <p v-if="message || slots.message" class="text-foreground text-sm font-medium"> <slot name="message">{{ message }}</slot> </p> </div> </Transition> </div> </template> <style scoped> .block-ui-fade-enter-active, .block-ui-fade-leave-active { transition: opacity 0.2s ease; } .block-ui-fade-enter-from, .block-ui-fade-leave-to { opacity: 0; } </style> -
app/components/ui/block-ui/block-ui.variants.ts 0.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> -
app/components/ui/block-ui/index.ts 0.1 kB
export { default as BlockUi } from './BlockUi.vue' export { blockUiVariants, type BlockUiVariants } from './block-ui.variants'
Raw manifest: https://uipkge.dev/r/vue/block-ui.json