Skip to main content

Backdrop

Backdrop is a wrapper that places content above a page or container, such as a custom dialog or contained panel.

Import

import { Backdrop } from '@vortexlabs/vortex';
import type { BackdropProps } from '@vortexlabs/vortex';

Allied components

Other links

"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.