Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

Modal: dialog

A modal is a window over the page that dims everything else and waits for an answer: confirm an action, fill in a short form. HTML has the <dialog> tag for it, and the browser can open and close it by itself. Pico adds the dimmed backdrop and styles the content as a card.

The modal markup

Inside <dialog> goes an <article> — the card from earlier lessons. A button with rel="prev" in the card header turns into a close cross:

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@picocss/pico@2/css/pico.min.css">
 
<div style="min-height: 280px"></div>
<dialog open>
  <article>
    <header>
      <form method="dialog">
        <button aria-label="Close" rel="prev"></button>
      </form>
      <p><strong>Thanks for subscribing!</strong></p>
    </header>
    <p>New blog posts will arrive on Fridays.</p>
  </article>
</dialog>

The modal is open right away thanks to the open attribute: the background is dimmed, and a card with a heading and a cross sits in the center. Click the cross and the modal closes. A button inside <form method="dialog"> closes its <dialog> without a single line of JavaScript. The empty min-height block gives the modal room in the preview.

Opening with a button

Usually the modal is hidden and a script opens it with the showModal() method. The close() method closes it, and so does the Escape key:

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@picocss/pico@2/css/pico.min.css">
 
<div style="min-height: 300px">
  <button id="open-contact">Contact me</button>
</div>
 
<dialog id="contact">
  <article>
    <header>
      <button aria-label="Close" rel="prev" data-close></button>
      <p><strong>Contact Anna</strong></p>
    </header>
    <label for="reply">Your email</label>
    <input type="email" id="reply">
    <footer>
      <button class="secondary" data-close>Cancel</button>
      <button data-close>Send</button>
    </footer>
  </article>
</dialog>
 
<script>
  const dialog = document.querySelector('#contact');
  document.querySelector('#open-contact').addEventListener('click', () => dialog.showModal());
  dialog.querySelectorAll('[data-close]').forEach((button) => {
    button.addEventListener('click', () => dialog.close());
  });
  dialog.addEventListener('close', () => console.log('Modal closed'));
</script>

Click "Contact me" — a modal opens with an email field and two buttons in the footer. Any of the three buttons or Escape closes it, and "Modal closed" appears under the example: the close event fires however the modal is closed.

What does what

PartJob
<dialog>The full-screen dimmed layer
<article>The modal card itself
<header> with rel="prev"The title and the cross
<footer>Action buttons aligned to the right
showModal() and close()Open and close from a script

showModal() also keeps focus inside the modal: the Tab key does not wander off to links on the page under the backdrop.

Common mistake

Opening the modal by simply adding the open attribute from a script. The modal appears, but the browser does not treat it as modal: Escape does not close it, and Tab moves focus to the page underneath. For windows that wait for an answer, use showModal().

Thanks for reading!

Donate to the site — we work hard for you.