AddThisFeature

Accessible Modal and Drawer Behaviour

Make overlays trap focus, close predictably, and stay usable without a mouse.

moderate Accessibility & Internationalization

What it adds

One shared overlay behaviour covering focus trapping, background inertness, escape handling, and scroll lock, applied to every modal, drawer, and popover panel in the app.

What your agent is told to do

6
  1. 1

    Find every overlay in the app — modals, drawers, sheets, command panels, image lightboxes — and route them through one implementation instead of fixing them individually.

  2. 2

    While an overlay is open, keep Tab and Shift+Tab cycling inside it and make the background inert so assistive technology cannot reach it. Hiding the background visually is not enough; a screen reader will still read straight through it.

  3. 3

    Give every overlay an accessible name from its visible title, and use dialog for things the user can dismiss versus alertdialog for interruptions that demand a decision.

  4. 4

    Lock background scrolling while open, compensating for the scrollbar width so the page does not shift sideways when the overlay appears.

  5. 5

    On close, return focus to whatever opened the overlay. If that trigger no longer exists — the row it lived in was deleted — fall back to a stable ancestor, and record the fallback rather than leaving it to chance.

  6. 6

    Do NOT let Escape close every open layer at once. It closes the topmost layer only, so a user dismissing a confirmation inside a drawer does not lose the drawer as well.

Edge cases it handles

7
  • An overlay with no focusable content still needs to receive focus itself, or the trap has nothing to hold.
  • Content added after open — a lazily loaded form, an appended row — must be inside the trap without rebuilding it.
  • Nested overlays need a stack: only the top layer is interactive, and closing it restores the trap to the layer beneath.
  • On iOS, locking scroll by hiding overflow on the body is not sufficient and lets the page scroll behind the overlay.
  • A drawer that pins open at desktop widths is no longer a dialog; it must stop trapping focus at that breakpoint.
  • An overlay opened by a keyboard shortcut has no trigger element, so it needs an explicit return target.
  • Closing must not depend on the backdrop existing — a full-bleed mobile sheet has no backdrop to click.

Definition of done

8
  • Every overlay in the app uses the same focus-trap and dismissal implementation.
  • Tab cannot leave an open overlay, and assistive technology cannot reach the background.
  • Escape closes only the topmost layer.
  • Each overlay has an accessible name and the correct dialog or alertdialog role.
  • Opening an overlay does not shift the page horizontally, and background scroll is locked including on iOS.
  • Focus returns to the trigger on close, or to a defined fallback when the trigger is gone.
  • The feature matches the existing design system.
  • No existing functionality is broken.

Related features

How it works

  1. 1

    Copy the link

    Grab the Markdown instruction URL for this feature.

  2. 2

    Give it to your AI

    Paste it into Claude Code, Cursor, v0, Lovable — whatever you build with.

  3. 3

    It inspects, then implements

    Your agent reads your existing app first, then adds the feature to fit it.

Works with your stack

These instructions are written to adapt. They tell the agent to detect your framework, match your existing design system, and reuse what you already have — rather than assuming a particular stack.

Need it tighter than that? Customize the feature and tell it exactly what you're running.