Jump to main content

The details and summary elements

  • Published:
  • Updated:
  • Category: html, accessibility

The details and summary elements are two of HTML’s interactive elements and together are the elements that create a native disclosure widget.

You may think of disclosure widgets by other names, but they’re most commonly recognized within the context of an accordion component. An accordion is comprised of various disclosure widgets that are often aware of each other’s current state.

More on disclosure widgets

A native disclosure widget does not keep track of the state of other sibling disclosure widgets, so if looking to create a common accordion interface, where opening one accordion panel closes any previously opened accordion panel, you're going to need some JavaScript.

And if you're viewing this page with a browser that supports details and summary, then you've just used a native disclosure widget to read this content.

General Support

Outside of Internet Explorer (which will never support the elements) and Edge (where development for these elements had started in May of 2017, but there’s yet to be any reported progress…) browser implementation of details and summary is otherwise pretty great!

For all the browsers that do support the elements, using them is fairly straight forward:

<details>
  <summary>
    <!-- Label for the disclosure widget -->
  </summary>
  <div> <!-- optional wrapper (for styling) -->
    <!-- collapsible content goes here -->
  </div>
</details>

With or without the optional div wrapper (which is only there for a wrapper to style), in its collapsed state the only visible element would be the summary and its contents.

Adding the open attribute to the details element will expand the nested content by default.

It’s worth noting that a summary element does not necessarily mean it must contain a “summary” of the other children of the details element. The HTML specification defines the element as representing “a summary, caption, or legend”, but you should treat the summary like you would any accordion trigger or toggle button. Provide it an appropriate accessible name to indicate the content it will reveal, and you’ll be good to go!

If you want to apply some custom styles to the elements, the trickiest part is working with the native triangle marker that visually conveys the expanded or collapsed state.

For non-Blink or Webkit based browsers (Firefox and maybe one day Edge…), you can style the marker using the list-style-image property.

summary {
  list-style-image: url('');
}

Blink and Webkit based browsers can style the marker with the following selector.

summary::-webkit-details-marker {
  /* ... */
}

For the browsers that don’t support the elements, the following markup would serve as a suitable stand-in:

<button type="button" aria-expanded="true/false" aria-controls="id_ref">
  <!-- Label for the disclosure widget -->
</button>
<div id="id_ref">
  <!-- collapsible content goes here -->
</div>

JavaScript would be needed to toggle the state of the aria-expanded value of the button. By following this basic markup structure, you could use CSS to toggle the visibility of the collapsible content.

button[aria-expanded="false"] + div {
  display: none;
}

With the above ruleset, the adjacent div to the button would be hidden while the button is in the collapsed state. When toggled to aria-expanded="true" the expanded state of the pattern would be conveyed, and since the selector no longer matched the state, the div would be reset to its inherent display: block;, revealing the previously hidden content.

That’s about as straight forward as it gets. More complicated markup patterns would likely necessitate revised functionality and CSS, but I’ve already written a bit about that in my Accessible Accordions post from 2017.

Screen Reader Support

Generally screen readers do well with standard usage of the details and summary elements. There are some variations in announcements depending on the screen reader and browser, but more importantly there are a few a bugs here and there to be aware of.

Depending on how you’re using the disclosure widget, at a high level it should be discoverable by form control or button screen reader quick keys. The summary should be focusable by the tab key. If headings are used, they should be discoverable by screen readers.

The test case for the following results has been posted to CodePen.

JAWS 2018 + Firefox (63 Nightly) and Chrome (latest)

JAWS with Firefox and Chrome will announce a native summary as its accessible name (the text of the summary), and the state of the disclosure widget when focused by virtual cursor or via the Tab key. The summary elements can also be navigated to by use of the B and F keys, like standard button elements.

When activated, JAWS + Firefox will announce the key used to toggle the disclosure widget (Space or Enter), the accessible name, role and updated state. JAWS + Chrome will announce the key pressed, and the updated state, but will not re-announce the accessible name and role.

JAWS with Firefox and Chrome will not announce, or allow users to navigate to, headings within a summary, even though using a heading within a summary is a valid content model. (a bug for this has been filed on the VFO standards support on GitHub).

There will be no change in announcements if the summary has a role="button" added to it (see VoiceOver and Safari on iOS).

VoiceOver and Safari on iOS 11.4.1

VoiceOver and Safari will announce a native summary as its accessible name, and the state of the disclosure widget, but offer no additional role announcement. The summary is not discoverable when navigating by form controls (for example, buttons) with the VoiceOver router.

VoiceOver will announce and allow navigation to a child heading of a summary element.

A role="button" can be added to the summary element to expose it as a button like other screen readers, however if a role="button" is added to the summary, then a heading will no longer be discoverable within the “button”.

Additionally, while testing I found that VoiceOver will continue to announce a disclosure widget as collapsed, regardless of state, if there is no <meta name="viewport"> set in the document. I’m not sure why that’d be an issue, but it made for an interesting, unexpected bug.

VoiceOver and Safari 11.1.2 on macOS 10.13.6

VoiceOver and Safari will announce a native summary as its accessible name, current state, and “summary” as the role. The summary element is not discoverable if navigating by form controls.

If a heading is nested within a summary it will be announced and discoverable by VoiceOver.

If using role="button" on a summary element, the element will be announced as a “button” but the state of the disclosure widget will not be announced. If a heading is nested within a summary role="button" it will be ignored by VoiceOver.

NVDA 2018.2.1 + Firefox (63 Nightly)

When using the Tab key, or virtual cursor to focus the summary element, NVDA will announce the accessible name (text of the summary), the current state of the widget (expanded or collapsed), and NVDA will announce the summary as a “button”.

Hitting Enter or Space will toggle the state of the widget, but no state change will be announced by NVDA with Firefox.

If “report role when mouse enters object” is turned on, NVDA will announce “button” and then the accessible name of the summary, when mouse hovering over the element. If a heading is within the summary, NVDA will announce “heading” instead, and will only announce “button” on the edges of the summary element (for example, if padding was set to the summary to push in the heading from its edges).

NVDA will expose and announce headings when used within summary elements.

NVDA 2018.2.1 + Chrome (latest)

NVDA will announce a summary in the same manner as noted with Firefox. However when togging the state of the widget, Chrome will announce the state change as “expanded” or “collapsed”, where Firefox did not to.

If NVDA’s “report role when mouse enters object” setting is checked, NVDA will announce “text” instead of “button”, when hovering over the element with a mouse.

NVDA will expose and announce headings when used within summary elements, however NVDA will no longer appropriately announce a state change when the summary is toggled (issue filed with NVDA).

Similarly, no state change will be announced with NVDA + Chrome if the summary has a role="button" to compensate for mobile VoiceOver not announcing a role for the summary element.

TalkBack (Android Accessibility Suite 6.2) + Android Chrome

TalkBack will announce a disclosure widget as “Collapsed, accessible name, disclosure triangle. Actions ‘expand’ double tap to activate.”

If the disclosure is expanded, “Expanded” will be announced as the state, and “Actions ‘collapse’” will be announced after TalkBack oddly (and uniquely) announces the existence of the default triangle marker.

Toggling the state of a disclosure widget will produce a standard sound effect and slight vibration, but no announcement of a state change will be made. Navigating away and back to the disclosure widget will have the new state declared as part of the announcement.

The summary element is discoverable when navigating by “controls” with TalkBack, but TalkBack ignores headings nested within the summary element.

If using summary role="button", TalkBack will modify it’s announcement of the disclosure widget to “State, accessible name, button.” Toggling the element will also not announce the changed state, but navigating away and back to the “button” will declare the new state in its announcement.

Wrapping up

Regardless of the few screen reader issues and inconsistencies, and lack of support for Microsoft browsers, details and summary are in a really good place. With a few fixes here and there, and when Microsoft implements these elements in Edge, details and summary can finally get the prime time attention they deserve.

In the meantime, you can use a polyfill with your own CSS to modify the elements for MicroSoft browsers…

<details>
  <summary aria-expanded="true/false" tabindex="0" role="button">
    My trigger
  </summary>
  <div>
    <!-- content goes here -->
  </div>
</details>

Or create a custom markup pattern like one of the following snippets…

<button aria-expanded="true/false" aria-controls="id_ref">
  My trigger
</button>
<div id="id_ref">
  <!-- content goes here -->
</div>

or

<h#>
  <button aria-expanded="true/false" aria-controls="id_ref">
    My trigger
  </button>
</h#>
<div id="id_ref">
  <!-- content goes here -->
</div>

…add in some light JavaScript to toggle the aria-expanded, and maybe toggle a class for the expansion panel, and you’ll have a suitable ARIA stand-in while details and summary get their last few kinks worked out.

As mentioned, there are issues filed for the Chrome + NVDA bug and JAWS concerning the use of headings within summary, which is a valid and useful markup pattern.

Additional Reading

For some more background on the details and summary elements, and the concept of disclosure widgets and accordions, check out the following: