Dialogs, overlays, and drawers

A dialog is more than a positioned box. It needs a sensible focus strategy, a way to close, keyboard behavior, and an appropriate accessible name. Use native <dialog> where it fits or a well-tested accessible dialog primitive. Tailwind handles the visual overlay and panel, but it does not trap focus or manage Escape behavior automatically.

Watch for clipping from ancestor overflow-hidden and stacking-context issues. A portal can help place overlays near the document root, but the component's behavior still needs to be implemented correctly.

Do not ship a visual-only dialog

A modal overlay that looks correct but allows keyboard focus to escape or leaves background controls interactive is incomplete. Use a tested accessible primitive or implement the full interaction contract.

Dialog visual structure (behavior omitted)
<div class="fixed inset-0 z-50 grid place-items-center bg-slate-950/50 p-4">
  <section role="dialog" aria-modal="true" aria-labelledby="confirm-title"
    class="w-full max-w-md rounded-2xl bg-white p-6 shadow-2xl">
    <h2 id="confirm-title" class="text-lg font-semibold text-slate-900">Delete this task?</h2>
    <p class="mt-2 text-sm leading-6 text-slate-600">This action cannot be undone.</p>
    <div class="mt-6 flex justify-end gap-3">
      <button class="rounded-lg border px-4 py-2 font-medium">Cancel</button>
      <button class="rounded-lg bg-red-600 px-4 py-2 font-semibold text-white">Delete task</button>
    </div>
  </section>
</div>
đź’ˇ This is a visual structure, not a complete accessible dialog implementation. Production code must manage opening/closing, initial focus, focus containment and restoration, Escape behavior, and background interaction according to the chosen dialog primitive.