Overlay Components
Overlay
A fullscreen backdrop overlay for creating modal backgrounds, loading screens, and lightbox effects. Renders via portal with click-to-close and optional blur.
A fullscreen backdrop overlay for creating modal backgrounds, loading screens, and lightbox effects. Renders via portal with click-to-close and optional blur.
Overlay ships its own layout defaults: fixed, flex, itemsCenter, justifyCenter. It covers the viewport via inset-0 and reads its z-index from a managed stacking context so nested overlays layer correctly. Modal is built on top of Overlay and reuses these defaults.
Basic Overlay
A fullscreen semi-transparent backdrop. Click the overlay background to dismiss.
const [open, setOpen] = useState(false);
<Button onClick={() => setOpen(true)}>Show Overlay</Button><Overlay open={open} onClose={() => setOpen(false)}> <Text>Click anywhere to close</Text></Overlay>Overlay with Content
Place content inside the overlay. Click handlers on the overlay only fire when the event target is the overlay itself, so children receive their own clicks without dismissing the overlay.
<Overlay open={open} onClose={() => setOpen(false)}> <Card> <Text>Overlay content here</Text> <Button onClick={() => setOpen(false)}>Close</Button> </Card></Overlay>Blur Effect
Add blur for a backdrop-filter blur behind the overlay. Blur intensity follows the --overlay-blur CSS variable.
<Overlay open={open} onClose={() => setOpen(false)} blur> <Card> <Text>Blurred background</Text> </Card></Overlay>Custom Backdrop Appearance
Style the backdrop with appearance + variant + shadow props, or pass a className for arbitrary background utilities. The example below uses danger filled for a tinted destructive backdrop.
<Overlay open={open} onClose={() => setOpen(false)} danger filled shadow> <Card> <Text>Tinted overlay</Text> </Card></Overlay>Use className for gradients or backgrounds the appearance system doesn't cover:
<Overlay open={open} onClose={() => setOpen(false)} className="bg-gradient-to-br from-black/80 to-transparent"> <Card> <Text>Custom gradient backdrop</Text> </Card></Overlay>Non-dismissible Overlay
Use pointerEventsNone for loading states where the overlay should pass clicks through and never close on its own. Useful for full-screen spinners that sit above the page.
<Overlay open={loading} pointerEventsNone> <Text>Loading...</Text></Overlay>Transparent Overlay
Use transparent to create an invisible backdrop that still captures clicks. Useful for click-away dismissal without visually dimming the page.
const [open, setOpen] = useState(false);
<Button onClick={() => setOpen(true)}>Show Transparent Overlay</Button><Overlay open={open} onClose={() => setOpen(false)} transparent> <Card> <Text>Content on a transparent overlay</Text> <Button onClick={() => setOpen(false)}>Close</Button> </Card></Overlay>Foundation for Modal
Modal is built on Overlay — the dialog surface renders inside an Overlay that handles portaling, backdrop click, and stacking. For accessible dialogs with focus trap, scroll lock, and ARIA wiring, prefer Modal. Reach for Overlay directly when you need a custom backdrop layer (lightbox, loading shade, drawer scrim) without dialog semantics.
{/* High-level: use Modal for dialogs */}<Modal open={open} onClose={() => setOpen(false)}> <Text>Accessible dialog with focus trap</Text></Modal>
{/* Low-level: use Overlay for custom backdrops */}<Overlay open={open} onClose={() => setOpen(false)} blur> <Img src="/photo.jpg" className="max-h-[90vh]" /></Overlay>Portal Target
Overlay renders into document.body by default via React portal. Set portal={false} to render in-place — useful when the overlay must be scoped to a positioned ancestor (e.g., scrim over a single card instead of the whole viewport).
<Card relative className="h-64"> <Text>Parent card</Text> <Overlay open={open} onClose={() => setOpen(false)} portal={false} absolute> <Text>Scoped to this card</Text> </Overlay></Card>When portal={false} and absolute is set, the overlay anchors to the nearest relative/absolute ancestor instead of the viewport.
Z-Index / Stacking
Overlay reads its z-index from a managed stacking context (--z-index), so multiple overlays stack in mount order automatically. Override per instance via inline style when you need to layer above a specific element (toasts, page chrome).
<Overlay open={open} onClose={() => setOpen(false)} style={{ '--z-index': 9999 } as React.CSSProperties}> <Card> <Text>Above everything</Text> </Card></Overlay>Custom Animation Duration
Control how the overlay transitions in and out. Use transitionDuration to set a custom duration in milliseconds (default 200), or noAnimation to disable transitions entirely for an instant open/close.
{/* Slow fade - 500ms */}<Overlay open={open} onClose={() => setOpen(false)} transitionDuration={500}> <Card>Slow transition content</Card></Overlay>
{/* Instant - no animation */}<Overlay open={open} onClose={() => setOpen(false)} noAnimation> <Card>Instant content</Card></Overlay>Lifecycle & Mounting
| Prop | Default | Description |
|---|---|---|
open | true | Whether the overlay is visible |
onClose | - | Called when the backdrop is clicked |
portal | true | Render into document.body via React portal |
keepMounted | false | Keep DOM mounted when closed (useful for transition state preservation) |
noAnimation | false | Disable enter/exit transitions |
transitionDuration | 200 | Animation duration in ms |
onEnterComplete | - | Called when enter transition completes |
onExitComplete | - | Called when exit transition completes |
<Overlay open={open} onClose={() => setOpen(false)} keepMounted transitionDuration={300} onExitComplete={() => console.log('overlay closed')}> <Card>Persistent DOM, custom timing</Card></Overlay>Overlay Props
| Prop | Category | Default | Description |
|---|---|---|---|
accent | Appearance | Accent color appearance (rose) | |
brand | Appearance | Brand color appearance (blue) | |
danger | Appearance | Danger color appearance (red) | |
info | Appearance | Info color appearance (cyan) | |
inherit | Appearance | Inherit appearance from parent — suppresses own data-appearance/data-variant, uses parent's CSS variables | |
link | Appearance | Link color appearance (blue, for hyperlinks) | |
primary | Appearance | Primary color appearance (gray) | |
secondary | Appearance | Secondary color appearance (gray) | |
success | Appearance | Success color appearance (green) | |
tertiary | Appearance | Tertiary color appearance | |
warning | Appearance | Warning color appearance (amber) | |
lg | Size | Large size | |
md | Size | Medium size (default) | |
sm | Size | Small size | |
xl | Size | Extra large size | |
xs | Size | Extra small size | |
filled | Variant | Filled variant - solid background with contrasting text color | |
ghost | Variant | Ghost variant - transparent background, no border, appearance-colored text, tinted hover background | |
outline | Variant | Outline variant - transparent background with border and colored text (default) |
Layout & utility props (gap, padding, hide, items, justify, ...) — documented on Common Props
| Prop | Category | Default | Description |
|---|---|---|---|
blur | Blur | Enable backdrop blur effect | |
noBlur | Blur | Disable backdrop blur effect | |
block | Display | Block display - takes full width, new line | |
contents | Display | Contents display - element's box is removed, children display as if parent didn't exist | |
flex | Display | ✓ | Flex display - flexbox container |
grid | Display | Grid display - CSS grid container | |
hidden | Display | Hidden display - element is not visible | |
inline | Display | Inline display - flows with text | |
inlineBlock | Display | Inline-block display - inline but with block properties | |
inlineFlex | Display | Inline-flex display - inline flexbox container | |
inlineGrid | Display | Inline-grid display - inline grid container | |
table | Display | Table display - behaves like table element | |
tableCell | Display | Table-cell display - behaves like td element | |
hAuto | Height | Set height to auto | |
hFit | Height | Set height to fit-content | |
hFull | Height | Set height to 100% | |
hScreen | Height | Set height to 100vh (viewport height), removes max-height constraint | |
desktopHide | Hide | Hide element on desktop devices and below (max-desktop: 80rem) | |
mobileHide | Hide | Hide element on mobile devices and below (max-mobile: 48rem) | |
tabletHide | Hide | Hide element on tablet devices and below (max-tablet: 64rem) | |
itemsBaseline | Items | Align items to baseline | |
itemsCenter | Items | ✓ | Align items to center |
itemsEnd | Items | Align items to end (bottom/right) | |
itemsStart | Items | Align items to start (top/left) | |
itemsStretch | Items | Stretch items to fill container | |
justifyAround | Justify | Distribute items with space around them | |
justifyBaseline | Justify | Align items along their baseline on main axis | |
justifyBetween | Justify | Distribute items with space between them | |
justifyCenter | Justify | ✓ | Center items along the main axis |
justifyEnd | Justify | Pack items toward the end of the main axis | |
justifyEvenly | Justify | Distribute items with equal space around them | |
justifyStart | Justify | Pack items toward the start of the main axis | |
justifyStretch | Justify | Stretch items to fill the main axis | |
overflowAuto | Overflow | Auto overflow - show scrollbars if needed | |
overflowClip | Overflow | Clip overflow - hard clip without scrollbars | |
overflowHidden | Overflow | Hidden overflow - clip content without scrollbars | |
overflowScroll | Overflow | Scroll overflow - always show scrollbars | |
overflowVisible | Overflow | Visible overflow - content extends beyond bounds | |
overflowXAuto | Overflow | Auto overflow on X-axis only | |
overflowXClip | Overflow | Clip overflow on X-axis only | |
overflowXHidden | Overflow | Hidden overflow on X-axis only | |
overflowXScroll | Overflow | Scroll overflow on X-axis only | |
overflowXVisible | Overflow | Visible overflow on X-axis only | |
overflowYAuto | Overflow | Auto overflow on Y-axis only | |
overflowYClip | Overflow | Clip overflow on Y-axis only | |
overflowYHidden | Overflow | Hidden overflow on Y-axis only | |
overflowYScroll | Overflow | Scroll overflow on Y-axis only | |
overflowYVisible | Overflow | Visible overflow on Y-axis only | |
pointerEventsAuto | Pointer Events | Enable pointer events (default browser behavior) | |
pointerEventsNone | Pointer Events | Disable pointer events - clicks pass through the element | |
absolute | Position | Absolute positioning | |
fixed | Position | ✓ | Fixed positioning |
relative | Position | Relative positioning | |
static | Position | Static positioning | |
sticky | Position | Sticky positioning | |
responsive | Responsive | Enable responsive sizing - uses breakpoint-specific classes for font size, padding, and gap | |
noRing | Ring | Disable focus ring | |
ring | Ring | Enable focus ring | |
noShadow | Shadow | Disable drop shadow | |
shadow | Shadow | Enable drop shadow | |
transparent | Transparent | Disable background color - makes component background transparent | |
wAuto | Width | Set width to auto | |
wFit | Width | Set width to fit-content | |
wFull | Width | Set width to 100% | |
wScreen | Width | Set width to 100vw (viewport width), removes max-width constraint |