콘텐츠로 이동

Backdrop — spec

Synthesized from MUI Backdrop. A semi-opaque overlay that dims the page behind a foreground element. Used by Modal, Drawer, Sheet, AlertDialog internally — and standalone for full-page loading screens.

When to use

  • Standalone: full-page loading state ("Saving... please wait").
  • Inside other components: as the scrim behind Modal / Drawer / Sheet (usually internal to those components).
  • Focus / attention: dim everything else to point at one task.

When NOT to use: - Modal-like UI — use Modal (it includes Backdrop). - Loading inside a card — use Skeleton or Spinner inline.

Anatomy

┌─────────────────────────────────────┐
│ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ │
│ ░░░░ (dimmed page content) ░░░░░░░░░ │
│ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ │
│ ░░░░░░░░░░░ [spinner] ░░░░░░░░░░░░░░ │
│ ░░░░░░░░░ Loading...  ░░░░░░░░░░░░░░ │
│ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ │
│ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ │
└─────────────────────────────────────┘

API

<Backdrop open={loading}>
  <CircularProgress />
</Backdrop>

<Backdrop open={open} onClick={() => setOpen(false)}>
  <p>Click anywhere to dismiss</p>
</Backdrop>
Prop Type Default Description
open boolean controlled Visibility
onClick () => void Click handler (often dismisses)
transitionDuration number 300 Fade ms
invisible boolean false Backdrop is transparent (still blocks clicks)
children ReactNode Foreground content (centered by default)

States

State Visual
Closed display: none
Opening Fade in from 0 to opacity (300ms)
Open Fully visible
Closing Reverse

Tokens consumed

--backdrop-bg                      (rgba(0,0,0,0.5) typical)
--backdrop-bg-light                (lighter for dark themes)
--motion-medium                    (fade duration)
--ease-out
--z-backdrop                       (above content, below modals/dialogs)

CSS

.backdrop {
  position: fixed;
  inset: 0;
  background: var(--backdrop-bg);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: var(--z-backdrop);
  opacity: 0;
  transition: opacity var(--motion-medium) var(--ease-out);
  pointer-events: none;
}

.backdrop[data-state="open"] {
  opacity: 1;
  pointer-events: auto;
}

@media (prefers-reduced-motion: reduce) {
  .backdrop { transition: opacity 0ms; }
}

Accessibility

  • Backdrop with content: usually wrap content in <div role="status" aria-live="polite"> (for loading) or <div role="alertdialog"> (for confirmations).
  • Standalone Backdrop is a focus trap when modal — keyboard can't escape until Backdrop closes.
  • Esc to close (when dismissible).
  • Click-outside to close (configurable).
  • aria-busy="true" on the entire affected page region during loading.

Code example — full-page loading

function App() {
  const { isAuthenticating } = useAuth();

  return (
    <>
      <Backdrop open={isAuthenticating}>
        <Stack align="center" gap={4}>
          <Spinner size="lg" color="white" />
          <Text color="white">로그인 ...</Text>
        </Stack>
      </Backdrop>

      <main>{/* main content */}</main>
    </>
  );
}

Edge cases

  • Multiple Backdrops at once: stack via z-index but visually messy. Avoid; use one at a time.
  • Backdrop doesn't cover virtual keyboard on mobile: position: fixed handles most, but iOS Safari has quirks with input focus.
  • Backdrop above modals: usually wrong — modals own their Backdrop. Don't double-stack.
  • Reduced motion: skip fade; instant.
  • Print: hide via @media print.

Don't

  • Don't use Backdrop where Modal / Drawer / Sheet handles it for you.
  • Don't make Backdrop too transparent — should clearly signal "background is inactive".
  • Don't make Backdrop too opaque (>0.7) — feels suffocating.
  • Don't disable Esc / click-outside without a clear dismiss button.
  • Don't pile multiple Backdrops.

References

  • MUI: Backdrop
  • Used internally by: Modal, Drawer, Sheet, AlertDialog

Cross-reference