John P. Rouillard
Posted on March 5, 2023
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:
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>
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;
}
The open popup looks like this:
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.
Posted on March 5, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.