Can a Details Element be Used as an Accessible Popup (Without JavaScript)?

rouilj

John P. Rouillard

Posted on March 5, 2023

Can a Details Element be Used as an Accessible Popup (Without JavaScript)?

I tried a little experiment to make a popup using a details element. The goal was to see if I could make a clickable popup without using JavaScript. It should be accessible for both sighted users and users using a screen reader like NVDA.

The HTML test case is a form with an info icon (the letter I in a circular blue field) after an input element. It is straightforward semantic HTML. The details element has a summary as its first element and a div enclosing paragraphs as the details' body. The summary element is the letter I styled using CSS to put the I (for info) on a circular lightblue field. The form looks like:

Image showing detail popup closed. The circular icon with an I in it used to open the popup has a light blue background color indicating it is closed. The rest of the screen displays labels, input fields, and one button at the bottom as you would see in a typical form.

The HTML is:

  <body>
    <form>
      <div>
    <span><label for="a">A label:</label> <input id="a">
      <details class="inline" aria-live="polite">
        <summary aria-label="Activate for info on A label.">I<!--<img src="logo.png">--></summary>
        <div>
          <p>
        Here is a popup/popover with some interesting information
        about the <b>A label</b> input field. It might also be very
        boring. The choice is up to you. But I would make it
        interesting if I were you.
          </p>
          <p><em>Use space to close.</em></p>
        </div>
      </details>
    </span>
    <span><label for="b">B label:</label> <input id="b">
      </div>
      <div>
        <span><label for="c">C label:</label> <input id="c"></span>
...
  </form>
</body>
Enter fullscreen mode Exit fullscreen mode

There is a small sprinkling of ARIA. The summary field's aria-label announces what happens when you open the details element. Originally I added aria-live="polite" on the div after the summary. But the detailed text was not announced when the details element opened. Moving aria-live to the details element, announced the text automatically when opened.

The summary icon trigger is opened by:

  • clicking on the icon with the mouse,
  • focusing on the icon (using tab) and
    • hitting space or
    • hitting return

Unlike other popups, this is triggered by a focusing user action rather than hover so it works on mobile as well.

The CSS was also rather straightforward. Changing the detail element's display to inline-block (default block) keeps it on the same line as the input. Changing the summary item's display to inline-block (default list-item) removes the open/close arrow associated with the details summary.

The icon was formed by using border-radius and background-color. To get things to align, I set the custom property --icon-size to the line height of the page. This property then gets used to square up (circle up 8-)) the shape of the summary text icon. You can use an image as well if you want. The background of the icon changes when opened, and can be seen through transparent parts of an image.

The details element (with the inline class) has its position set to relative. This makes positioning the div containing the detailed text easier. The div itself uses position: absolute. With these settings, the attributes left, top, right, and bottom can be used to shift the div relative to its default location.

This is the complete CSS:

/* styles for details popup */
:root { --icon-size: calc(1.5em); /* line height */ }
details.inline {
  display: inline-block;
  position: relative; /* anchor popup position */
}
details.inline summary {
  background-color: lightblue;
  border: 1px black solid;
  border-radius: 50%;
  cursor: default;
  display: inline-block;  /* remove marker */
  font-weight: bold;
  height: var(--icon-size); /* make icon round */
  text-align: center;
  width:var(--icon-size); /* make icon round */
}
details.inline summary img {
  /* if you want to use an image */
  height: var(--icon-size);
  width: var(--icon-size);
}
details.inline > div > * {
  margin-block: 0.25em;
  padding-inline: 0.25em;
}
details.inline[open] summary { background-color: yellow; }
details.inline[open] > div {
  background-color: white;
  border: 2px inset black;
  border-radius: 1em;
  left: -10ch; /* shift box to left */
  /* Move the popup box after the icon with
     a 5px gap */
  /* left: calc(var(--icon-size) + 5px); */
  position: absolute;
  /* To align first line of popup with the baseline of the icon:
   * shift up by 1/3 of the line height (--icon-size * -0.3333)
   * then shift down by the margin-block on the div (+ 0.25em).
   * This turns out to be 0.25em. */
  /*top: calc((var(--icon-size) * -0.333) + 0.25em);*/
  width: 40ch;
}
Enter fullscreen mode Exit fullscreen mode

The open popup looks like this:
Image showing detail popup open. The circular icon with an I in it used to open/close the popup has a yellow background color indicating it is open. The popup sits on top of other text on the page. It is shifted to the left under the opening icon.

Prettier styling is an exercise for the reader 8-).

It can be enhanced with JavaScript to:

  • close with a keypress (using the escape key for example)
  • close with a mouse click outside of the popup
  • (see: details-utils)

Even without JavaScript, it is usable in Firefox and Chrome (which includes browsers like Edge, Brave, Vivaldi...). The details element should be accessible out of the box since it is a native HTML control. Although I only tested with NVDA and Windows Narrator, I expect it will work with other screen readers as well. (Note that Narrator would sometimes refuse to read the popup when opened. I have not discovered what causes it to refuse to read the popup on open. Moving the cursor with the right arrow key causes it to read the popup, and pressing the space key still closes the popup so....)

This seems to be a successful experiment. Custom variables, details element, and calc are all well supported. This technique should work on the majority of browsers out there today.

This technique will probably make it into some of the trackers I design for the Roundup Issue Tracker.

Leave your quips, comments, evasions, questions, or answers below.

💖 💪 🙅 🚩
rouilj
John P. Rouillard

Posted on March 5, 2023

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related