UIPackage
Menu

Block Ui

block-ui ui
Edit on GitHub

Overlay that blocks interaction during loading. Wraps content and shows a spinner + message overlay. The blocking prop toggles the blocked state with configurable overlay opacity, color, background blur, and custom icon/message slots. Composes the spinner primitive.

Also available for Vue ->

Installation

$ npx shadcn@latest add https://uipkge.dev/r/react/block-ui.json
Named registry: npx shadcn@latest add @uipkge-react/block-ui Installs to: components/ui/block-ui/

Examples

Props

Name Type / Values Default Required
blocking

When true, the overlay is shown and the wrapped content is blocked.

boolean optional
message

render prop is supplied via children.

React.ReactNode optional
opacity number optional
overlayColor string optional
blur boolean optional
showSpinner boolean optional
icon

Custom icon node replacing the default Spinner (Vue #icon slot).

React.ReactNode optional
messageSlot

Custom message node replacing the `message` string (Vue #message slot).

React.ReactNode optional

npm dependencies

Includes

Files installed (3)

  • components/ui/block-ui/BlockUi.tsx 2.7 kB
    import * as React from 'react'
    import { cn } from '@/lib/utils'
    import { blockUiVariants } from './block-ui.variants'
    import { Spinner } from '@/components/ui/spinner'
    
    export interface BlockUiProps extends React.HTMLAttributes<HTMLDivElement> {
      /** When true, the overlay is shown and the wrapped content is blocked. */
      blocking?: boolean
      /** Plain-text or rich message shown under the icon. Ignored when a message
       *  render prop is supplied via children. */
      message?: React.ReactNode
      opacity?: number
      overlayColor?: string
      blur?: boolean
      showSpinner?: boolean
      /** Custom icon node replacing the default Spinner (Vue #icon slot). */
      icon?: React.ReactNode
      /** Custom message node replacing the `message` string (Vue #message slot). */
      messageSlot?: React.ReactNode
    }
    
    const BlockUi = React.forwardRef<HTMLDivElement, BlockUiProps>(
      (
        {
          className,
          children,
          blocking = false,
          message = 'Loading...',
          opacity = 0.6,
          overlayColor = '',
          blur = false,
          showSpinner = true,
          icon,
          messageSlot,
          ...props
        },
        ref,
      ) => {
        const overlayStyle: React.CSSProperties = React.useMemo(() => {
          const style: React.CSSProperties = { opacity }
          if (overlayColor) style.backgroundColor = overlayColor
          return style
        }, [opacity, overlayColor])
    
        return (
          <div
            ref={ref}
            data-uipkge=""
            data-slot="block-ui"
            data-blocked={blocking ? '' : undefined}
            className={cn(blockUiVariants(), className)}
            {...props}
          >
            {/* Wrapped content */}
            <div
              className={cn(
                'block-ui-content',
                blur && blocking && 'pointer-events-none blur-[2px] transition-[filter]',
              )}
            >
              {children}
            </div>
    
            {/* Blocking overlay */}
            {blocking && (
              <div
                className="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
                  className={cn('absolute inset-0', !overlayColor && 'bg-background')}
                  style={overlayStyle}
                />
                {/* Content layer (spinner + message stay fully opaque) */}
                {icon ?? (showSpinner && <Spinner size="lg" />)}
                {messageSlot ? (
                  <div className="text-foreground text-sm font-medium">{messageSlot}</div>
                ) : (
                  message && <p className="text-foreground text-sm font-medium">{message}</p>
                )}
              </div>
            )}
          </div>
        )
      },
    )
    BlockUi.displayName = 'BlockUi'
    
    export { BlockUi }
  • 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>
  • components/ui/block-ui/index.ts 0.1 kB
    export { BlockUi, type BlockUiProps } from './BlockUi'
    export { blockUiVariants, type BlockUiVariants } from './block-ui.variants'

Raw manifest: https://uipkge.dev/r/react/block-ui.json