Modal windows: when they are needed and how to make them right

When a window is justified, what it consists of, a bottom sheet on a phone, the keyboard focus, pop-ups on entry and the native dialog element — with live examples.

Interface elements Updated

In short

A modal window interrupts the person, so it is used only when an answer is needed right now: to confirm a deletion, to fill in one short field, to look at a product without leaving the catalogue. Long forms, policies and checkout belong on pages, and a subscription offer belongs after the text, not on top of it at entry. A good window says in the title what it is about, has three ways out — the close button, Esc and Cancel — keeps the keyboard focus inside and returns it to the button that opened it. The page behind is dimmed and does not scroll. On a phone the window becomes a sheet at the bottom of the screen with full-width buttons under the thumb. The native <dialog> element does most of this by itself.

A window or not

Eight common cases. A window is right when the task is short and the answer is needed now.

  • Confirm a deletion

    A window

    Short, needs an answer right now, and what is being deleted stays visible behind.

  • A one-field “Call me back” form

    A window

    The person stays on the page they were reading.

  • A quick product preview

    Can be

    Saves a trip, but the full product page must still exist.

  • Choosing a size or a colour

    Can be

    On a phone — as a sheet at the bottom.

  • A subscription offer on entry

    Not a window

    The person has not read anything yet. A block after the text works better.

  • Checkout

    Not a window

    A page with steps: it has a Back button and survives a reload.

  • Terms and privacy policy

    Not a window

    Long text that needs its own address.

  • A “Saved” message

    Not a window

    A quiet notification that disappears by itself.

What a window consists of

Six parts. Three of them are ways out: the close button, Esc and the backdrop.

  1. Title — what this window is about, no “Attention!”
  2. Close — in the top right corner, 44 × 44
  3. Content — one task, no scrolling inside the window
  4. Actions — the main one last, its label repeats the point
  5. Backdrop — dims the page; a click on it closes the window if nothing was typed
  6. Esc — closes the window from the keyboard

On a phone — a sheet at the bottom

A window in the centre of a phone screen is far from the thumb. A sheet puts the same buttons at the bottom, full width.

Desktop: in the centre
Phone: a bottom sheet

In a sheet the main action goes on top of the column, and the grab bar shows that the sheet can be pulled down. If the content does not fit in half the screen, it is no longer a sheet but a page.

The focus stays inside

From the keyboard, Tab walks in a circle inside the window. The page behind cannot be reached, and after closing the focus returns to where it was.

Without this, a keyboard user tabs out of the window into an invisible page, and after closing finds themselves at the top of the document. <dialog> opened with showModal() keeps the focus inside, closes on Esc and makes the page behind inert — no extra library is needed.

A window in code: 3 examples

The native <dialog>: markup with a form that closes the window, styles with a sheet for phones, and a script for opening and the backdrop.

Markup

A form with method="dialog" closes the window; the value of the pressed button says how.

dialog.html
<button class="button" type="button" data-open="callback">Call me back</button>

<dialog class="dialog" id="callback" aria-labelledby="callback-title">
  <form class="dialog__body" method="dialog">
    <h2 id="callback-title">We will call you back</h2>
    <button class="dialog__close" value="cancel" formnovalidate aria-label="Close">✕</button>

    <label for="callback-phone">Phone</label>
    <input id="callback-phone" name="phone" type="tel" autocomplete="tel" required>

    <div class="dialog__actions">
      <button class="button button--ghost" value="cancel" formnovalidate>Cancel</button>
      <button class="button" value="send">Call me back</button>
    </div>
  </form>
</dialog>

Styles

The backdrop, the page that does not scroll, and a sheet on narrow screens.

dialog.css
.dialog {
  width: min(100% - 2rem, 34rem);
  padding: 0;            /* the padding lives inside: a click on the dialog itself is a click on the backdrop */
  border: 0;
  border-radius: var(--radius-lg);
}

.dialog__body {
  display: grid;
  gap: var(--space-3);
  padding: var(--space-5);
}

.dialog::backdrop {
  background: rgb(23 24 23 / 0.6);
}

/* The page behind does not scroll */
html:has(.dialog[open]) {
  overflow: hidden;
}

/* On a phone: a sheet at the bottom with full-width buttons, the main one on top */
@media (max-width: 47.99rem) {
  .dialog {
    width: 100%;
    max-width: none;
    margin: auto 0 0;
    border-radius: var(--radius-lg) var(--radius-lg) 0 0;
  }

  .dialog__actions {
    display: flex;
    flex-direction: column-reverse;
    gap: var(--space-2);
  }
}

Opening and the backdrop

showModal() does the hard part; the script adds closing by the backdrop and the return of the focus.

dialog.js
// The button opens its window; after closing, the focus returns to the button
for (const opener of document.querySelectorAll('[data-open]')) {
  const dialog = document.getElementById(opener.dataset.open);
  opener.addEventListener('click', () => {
    dialog.showModal();
    dialog.addEventListener('close', () => opener.focus(), { once: true });
  });
}

// A click on the backdrop closes the window — unless something has been typed
for (const dialog of document.querySelectorAll('dialog')) {
  dialog.addEventListener('click', (event) => {
    const typed = [...dialog.querySelectorAll('input, textarea')].some((field) => field.value);
    if (event.target === dialog && !typed) dialog.close('cancel');
  });
}

7 rules for modal windows

  1. 01

    Only when the answer is needed now

    Everything else — a page, a block or a notification.

  2. 02

    A title that says what it is about

    “Remove from the cart?”, not “Attention!”.

  3. 03

    Three ways out

    The close button, Esc and Cancel; the backdrop — if nothing has been typed.

  4. 04

    The focus inside and back

    Tab does not leave the window, and after closing returns to the button.

  5. 05

    A sheet on a phone

    Buttons at the bottom, full width, under the thumb.

  6. 06

    One window at a time

    The next step replaces the content instead of opening a window on top.

  7. 07

    Not on entry

    A window opens in response to an action of the person.

Common mistakes with modal windows

  1. A pop-up in the first second

    People close it without reading and remember the annoyance.

  2. A tiny or late close button

    The person looks for a way out instead of reading.

  3. The backdrop erases what was typed

    One click past the window — and the form has to be filled in again.

  4. The page scrolls behind

    After closing, the person is in a different place on the page.

  5. A window on top of a window

    It is not clear which one closes and where the person returns.

  6. A long form in a window

    A scroll inside a scroll, and on a phone the buttons are out of reach.

Questions about modal windows

A modal window or a separate page?

A page if the content is long, needs its own address or a Back button. A window for a short task without leaving the page.

Should a click on the backdrop close the window?

Yes, if nothing has been typed. If the person has started filling in a form, a click past the window should not erase it.

What does the dialog element give?

Opened with showModal(), it dims the page, keeps the focus inside, closes on Esc and is understood by screen readers. All modern browsers support it.

How should a modal window look on a phone?

As a sheet at the bottom with full-width buttons. If the content is longer than half the screen, it is better as a page.

Can a window open by itself?

Only for important warnings, like the end of a session. Everything else opens in response to an action.

How wide should a window be?

As wide as the content needs without scrolling inside; for dialogs with text — up to about 560 px.

Online form

Windows that
do not annoy

I design and build interfaces where dialogs appear only when needed and close the way people expect. Tell me about the project — I answer within one working day.

Or write to [email protected]