Tailwind Modals and Dropdowns

A modal is a window that appears on top of the page and asks for attention. A dropdown is a small panel that opens beneath a button. Both patterns hide content until a visitor asks for it. Modern HTML includes built-in elements for each, and Tailwind styles them without a heavy script.

The Anatomy of a Dropdown

A dropdown has two parts: a trigger that the visitor clicks and a panel that holds the choices. The panel floats above the page content without moving anything.

Closed                   Open
┌───────────┐            ┌───────────┐
│ Options ▾ │            │ Options ▴ │
└───────────┘            ├───────────┤
                         │ Profile   │
                         │ Settings  │
                         │ Sign out  │
                         └───────────┘

A Dropdown With the Details Element

The HTML details element opens and closes on click with no script. The summary acts as the trigger. Position the panel with absolute inside a relative parent.

<details class="relative inline-block">
  <summary class="cursor-pointer list-none rounded bg-sky-600 px-4 py-2 text-white">
    Options
  </summary>
  <ul class="absolute left-0 z-20 mt-2 w-40 rounded border bg-white py-1 shadow-lg">
    <li><a href="#" class="block px-4 py-2 hover:bg-gray-100">Profile</a></li>
    <li><a href="#" class="block px-4 py-2 hover:bg-gray-100">Settings</a></li>
  </ul>
</details>

The class list-none removes the default arrow marker from the summary. The open: variant styles the element while it stays open, such as open:bg-gray-100.

The Layer Order

A panel needs a z-index above nearby content, or sticky headers and cards cover it. The value z-20 works for dropdowns, and z-50 works for modals.

A Modal With the Dialog Element

The native dialog element handles three hard jobs: it draws above everything, it traps keyboard focus inside, and it closes when a visitor presses the Escape key. Tailwind includes a backdrop: variant for the dimmed layer behind the window.

<button id="open" class="rounded bg-sky-600 px-4 py-2 text-white">Open</button>

<dialog id="box" class="m-auto w-full max-w-md rounded-xl p-6 shadow-xl backdrop:bg-black/50">
  <h3 class="text-lg font-bold">Save changes?</h3>
  <p class="mt-2 text-gray-600">Your edits will update the page.</p>
  <form method="dialog" class="mt-6 flex justify-end gap-3">
    <button class="rounded border px-4 py-2">Cancel</button>
    <button class="rounded bg-sky-600 px-4 py-2 text-white">Save</button>
  </form>
</dialog>

<script>
  const box = document.getElementById("box");
  document.getElementById("open").addEventListener("click", () => box.showModal());
</script>

A form with method="dialog" closes the window when any button inside it is pressed. No extra code is needed for the close action.

Modal Layer Diagram

┌──────────────────────────────────────┐
│ page content (dimmed by backdrop)    │
│        ┌──────────────────┐          │
│        │ Save changes?    │          │
│        │ [Cancel]  [Save] │          │
│        └──────────────────┘          │
└──────────────────────────────────────┘

Why Native Elements Come First

Custom modals built from plain divs demand a long list of behaviors. Developers must dim the background, move focus inside, trap the Tab key, close on Escape, restore focus afterward, and hide the page from screen readers. Missing any step frustrates keyboard and assistive technology users. The native dialog element performs these steps on its own, which saves code and removes mistakes.

The same idea applies to dropdowns. The details element already tracks its open state and responds to the keyboard. Tailwind only adds the look. Smaller scripts load faster, which helps visitors on slow connections.

Accessibility Checklist

  • Add a clear heading inside every modal so screen readers announce its purpose.
  • Provide a visible close button or Cancel option.
  • Return focus to the trigger button after the modal closes. The dialog element handles this step.
  • Avoid opening a modal automatically on page load. Visitors find it disruptive.

Keyboard Behavior for Dropdowns

Mouse users click, while keyboard users press Enter or Space on the summary and Tab through the links. Ensure each link shows a focus ring with focus:bg-gray-100 focus:outline-none or the default outline. Long menus may need arrow key support, which requires a small script or a library.

When to Use a Library

Native elements cover simple cases. Complex menus with nested items, search boxes, and arrow key navigation take more work. Headless libraries such as Headless UI and Radix UI provide the behavior and leave all styling to your Tailwind classes. Start with native elements, and move to a library when the interaction grows.

Keep modals for decisions that need focus: confirmations, short forms, and image previews. Long content belongs on its own page, where visitors can scroll, bookmark, and share it easily.