Backdrop
A full-screen overlay that traps focus, locks scroll, and closes on click-away or Esc — the primitive behind Alert and other modal surfaces.
Overview
Backdrop renders a dark overlay that covers the viewport (or a relative parent) and positions child content on top of it. It handles:
- Scroll lock —
document.body.overflowis set tohiddenwhile open, and padding is added to compensate for the removed scrollbar. - Focus trap — keyboard focus is constrained to the children while the backdrop is open.
- Click-away and Esc —
onCloseis called when the user clicks outside the children or presses Esc. - Mount/unmount lifecycle — children are mounted on open and unmounted after the closing transition completes.
Backdrop is the building block used by Alert. Use it directly when you need a custom modal surface.
Import
import { Backdrop } from '@unflow.io/ui/components/Backdrop';Props
| Prop | Type | Default | Description |
|---|---|---|---|
open | boolean | — | Controls visibility |
onClose | () => void | — | Called on click-away or Esc |
children | ReactElement | — | Required. Content rendered over the overlay |
disablePortal | boolean | — | Use absolute positioning relative to parent instead of fixed viewport overlay |
keepMounted | boolean | — | Keep children mounted (invisible) in the DOM while closed, instead of unmounting them |
autoFocus | boolean | — | Move focus into children when the backdrop opens |
Basic usage
'use client';
import { useState } from 'react';
import { Backdrop } from '@unflow.io/ui/components/Backdrop';
import { Button } from '@unflow.io/ui/components/Button';
export function Example() {
const [open, setOpen] = useState(false);
return (
<>
<Button label="Open backdrop" onClick={() => setOpen(true)} />
<Backdrop open={open} onClose={() => setOpen(false)}>
<div className="bg-white rounded-lg shadow-lg p-6">
<p className="text-sm font-medium">Custom content over backdrop</p>
<Button label="Close" variant="secondary" size="sm" onClick={() => setOpen(false)} />
</div>
</Backdrop>
</>
);
}Relative to parent
Set disablePortal to render the backdrop inside its DOM parent with absolute positioning instead of as a fixed viewport overlay. The parent element must have position: relative and a defined size.
<div className="relative h-64 w-full border rounded-lg overflow-hidden">
<Button label="Open" onClick={() => setOpen(true)} />
<Backdrop open={open} disablePortal onClose={() => setOpen(false)}>
<div className="bg-white rounded-lg shadow-lg p-6">
<p className="text-sm">Contained to parent</p>
</div>
</Backdrop>
</div>Custom backdrop overlay
Replace the default bg-black/30 dark overlay using slotProps.backdrop. Any Tailwind class or inline style can be applied.
<Backdrop
open={open}
onClose={() => setOpen(false)}
slotProps={{ backdrop: { className: 'bg-brand-500/40' } }}
>
<div className="bg-white rounded-lg p-6">Content</div>
</Backdrop>To replace the overlay element entirely (e.g. with a blurred surface), use slots.backdrop:
<Backdrop
open={open}
onClose={() => setOpen(false)}
slots={{ backdrop: <span className="absolute inset-0 backdrop-blur-sm bg-white/10" /> }}
>
<div className="bg-white rounded-lg p-6">Content</div>
</Backdrop>Customization (slotProps)
| Slot | Props | Description |
|---|---|---|
backdrop | BaseHTMLProps<HTMLSpanElement> | The dark overlay <span> behind the children |
Accessibility
- The container itself carries no ARIA role — it's a generic overlay wrapper. Give the content you pass as
childrenits ownrole(e.g.dialog/alertdialog) and accessible name, as Alert and Modal do. - Focus is trapped within
childrenwhile open, preventing keyboard users from tabbing to background content. - Pressing Esc triggers
onClose— always wire this to actually close the overlay. - Set
autoFocusto move focus into the children when the backdrop opens, so keyboard and screen-reader users land in the right place. - Scroll lock prevents background content from scrolling while the overlay is open. The removed scrollbar width is compensated with
paddingRightto avoid layout shift.
List
A generic, accessible list that owns keyboard navigation, focus and virtualization, delegating row rendering to a `renderItem` callback — pair it with ListItem for ready-made rows.
Alert
A modal alert dialog for confirmations, notifications, and destructive actions — with semantic types, footer actions, and an optional hint checkbox.