"use client";
import { Backdrop, Button, Card, Stack, Text } from "@vortexlabs/vortex";
import React from "react";
export const BackdropUsage = () => {
const [open, setOpen] = React.useState(false);
return (
<>
<Button onClick={() => setOpen(true)}>Open backdrop</Button>
<Backdrop active={open} onClose={() => setOpen(false)}>
<Card
width="min(24rem, calc(100vw - 2rem))"
attributes={{
role: "dialog",
"aria-modal": true,
"aria-label": "Project details",
tabIndex: -1,
}}
>
<Stack gap={4}>
<Text>Review the project details before continuing.</Text>
<Button onClick={() => setOpen(false)}>Close details</Button>
</Stack>
</Card>
</Backdrop>
</>
);
};Features
- Covers the page or a container.
- Requests closing on Escape or backdrop clicks.
- Supports dimming, blur, and click-through.
- Traps focus and restores it on close.
- Locks page or container scroll for blocking backdrops.
Close Requests
Use onClose to read the dismissal reason: backdrop-click or escape-key.
Last close: Not closed yet
"use client";
import { Backdrop, Button, Card, Stack, Text } from "@vortexlabs/vortex";
import React from "react";
export const BackdropReasons = () => {
const [open, setOpen] = React.useState(false);
const [reason, setReason] = React.useState("Not closed yet");
return (
<Stack gap={3}>
<Button onClick={() => setOpen(true)}>Inspect close reason</Button>
<Text>Last close: {reason}</Text>
<Backdrop
active={open}
onClose={({ reason }) => {
setReason(reason);
setOpen(false);
}}
>
<Card
attributes={{
role: "dialog",
"aria-modal": true,
"aria-label": "Close reason",
tabIndex: -1,
}}
>
<Stack gap={4}>
<Text>Press Escape or select the backdrop.</Text>
<Button
onClick={() => {
setReason("close-button");
setOpen(false);
}}
>
Close
</Button>
</Stack>
</Card>
</Backdrop>
</Stack>
);
};Backdrop Clicks
Set closeOnBackdropClick={false} to ignore backdrop clicks. Escape still requests dismissal.
"use client";
import { Backdrop, Button, Card, Stack, Text } from "@vortexlabs/vortex";
import React from "react";
export const BackdropPersistent = () => {
const [open, setOpen] = React.useState(false);
return (
<>
<Button onClick={() => setOpen(true)}>Open persistent backdrop</Button>
<Backdrop
active={open}
closeOnBackdropClick={false}
onClose={() => setOpen(false)}
>
<Card
attributes={{
role: "dialog",
"aria-modal": true,
"aria-label": "Persistent backdrop",
tabIndex: -1,
}}
>
<Stack gap={4}>
<Text>Backdrop clicks keep this panel open.</Text>
<Button onClick={() => setOpen(false)}>Done</Button>
</Stack>
</Card>
</Backdrop>
</>
);
};Dimming and Blur
Set transparent from 0 (dim) to 1 (clear) to adjust dimming while blocking clicks. Set blurred to blur the background.
Use transparent={true} for a clear, click-through backdrop; focus remains trapped.
"use client";
import { Backdrop, Button, Card } from "@vortexlabs/vortex";
import React from "react";
export const BackdropAppearance = () => {
const [open, setOpen] = React.useState(false);
return (
<>
<Button onClick={() => setOpen(true)}>Open blurred backdrop</Button>
<Backdrop active={open} transparent={0.5} blurred onClose={() => setOpen(false)}>
<Card
attributes={{
role: "dialog",
"aria-modal": true,
"aria-label": "Blurred backdrop",
tabIndex: -1,
}}
>
<Button onClick={() => setOpen(false)}>Close blurred backdrop</Button>
</Card>
</Backdrop>
</>
);
};Contained Backdrops
Set containerRef to render inside an element and lock its scrolling. Give that container position="relative".
This panel contains its own backdrop.
"use client";
import { Backdrop, Button, Card, Stack, Text } from "@vortexlabs/vortex";
import React from "react";
export const BackdropContained = () => {
const containerRef = React.useRef<HTMLDivElement>(null);
const [open, setOpen] = React.useState(false);
return (
<Stack
position="relative"
minHeight="16rem"
padding={4}
borderColor="default"
borderRadius="md"
attributes={{ ref: containerRef }}
>
<Button onClick={() => setOpen(true)}>Open contained backdrop</Button>
<Text>This panel contains its own backdrop.</Text>
<Backdrop
containerRef={containerRef}
active={open}
onClose={() => setOpen(false)}
>
<Card
attributes={{
role: "dialog",
"aria-label": "Contained backdrop",
tabIndex: -1,
}}
>
<Button onClick={() => setOpen(false)}>Close contained backdrop</Button>
</Card>
</Backdrop>
</Stack>
);
};Accessibility
Key
Description
Escape
Requests closing through
onClose.TabShiftTab
Move focus between controls inside the backdrop.
Give dialog content
role="dialog" and an accessible name through aria-label or aria-labelledby.Set
aria-modal={true} on dialogs that block the page and provide a visible close button.