<details> Tag

Creating a Menu

Introduction

There are accessibility problems with the hidden checkbox hack used for many CSS only menus, including the one at the top of this page.

The HTML and CSS standards are changing all the time and one of the newest HTML tags being worked on is a fork of the <select> tag which was named <selectmenu> but currently named <selectlist>. The control was first announced in August 2020 but in January 2024 is still under development. I am excited about this new tag and foresee that at some time this will become the main menu for this site.

In the meantime I took a look at the <details> tag which was introduced around 2011, and what that can do. I particularly wanted to do this as the <details> tag is made to be accessible. It is both tabbable and can be opened and closed using either the Enter key or Spacebar.


Testing

This page was tested in Chrome (120.0.6099.200), Edge (120.0.2210.133), Forefox (121.0.1) and Opera (106.0.4998.28).

I couldn't think of or find a way of closing the details tag without using JavaScript, so JavaScript must be enabled for the tags to work properly.


The <Details> Tag

The <details> tag is designed to show a piece of text which when clicked on, displays a longer text...

Lorem Ipsum...

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.


Normal Vertical Behaviour

How it works makes it usable for vertical accordian menus...

Lorem Ipsum...

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.

Sed ut perspiciatis...

Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam eaque ipsa, quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt, explicabo.

At vero eos et accusamus...

At vero eos et accusamus et iusto odio dignissimos ducimus, qui blanditiis praesentium voluptatum deleniti atque corrupti, quos dolores et quas molestias excepturi sint, obcaecati cupiditate non provident, similique sunt in culpa, qui officia deserunt mollitia animi,

This type of menu is great in that the details elements can simply be clicked on to be opened and closed and are keyboard tabbable and can be opened and closed using the spacebar or Enter key. They cannot be closed using the Esc key.


Open One, Close Another

A problem wih them when used as menus is that of grouping. When one is open and another is opened, then the first opened is not automatically closed. This problem has been addressed using JavaScript on Stack Overflow. Adapting the shortest code on that, this can be produced...

Lorem Ipsum...

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.

Sed ut perspiciatis...

Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam eaque ipsa, quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt, explicabo.

At vero eos et accusamus...

At vero eos et accusamus et iusto odio dignissimos ducimus, qui blanditiis praesentium voluptatum deleniti atque corrupti, quos dolores et quas molestias excepturi sint, obcaecati cupiditate non provident, similique sunt in culpa, qui officia deserunt mollitia animi,

This is done by giving the <details> tags a class of "dettesta" and using the JavaScript:

<script type="text/javascript">
	document.querySelectorAll('.dettesta').forEach((D,_,A)=>{ D.ontoggle =_=>{ if(D.open) A.forEach(d =>{ if(d!=D) d.open=false })}
})
</script>

This shortest JavaScript is not particularly readable, so it may be sensible to use one of the longer pieces of code.


Default is Vertical!

I want them to line up the <details> tags horizontally like this...

Lorem Ipsum...

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.

Sed ut perspiciatis...

Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam eaque ipsa, quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt, explicabo.

At vero eos et accusamus...

At vero eos et accusamus et iusto odio dignissimos ducimus, qui blanditiis praesentium voluptatum deleniti atque corrupti, quos dolores et quas molestias excepturi sint, obcaecati cupiditate non provident, similique sunt in culpa, qui officia deserunt mollitia animi,

This was done by giving the details tag a class of dettestb and the CSS changed to make them inline using this: .dettestb { display:inline; }


Relative Positioning

Now there's a new problem. When the details summary text is clicked on and the full text opened then the other detail tags move to follow the opened text.

One was of resolving this is by removing the details tags from the normal flow of the page, putting them in a new relative positioned div and giving the details tag both a class name and an ID, then positioning them in the new container div.

One problem I came across while writing this was that when giving the <details> tag a width of 100% and moving them, the original DOM boxes would calculate the width of them which caused them to overflow the page on the right. This shouldn't be a problem if the conents are designed to not be too long, where they are, I solved this by setting the section the menu is in to have overflow-x:hidden;. When doing this, the section must be tall enough to contain the main <details> tag text.

To demonstrate what is happening, the summaries have a surrounding red border, and the main details text a blue border.

I have also coloured the background of the details text to make it plain what is happening. The cursor is also changed to the pointed finger when the summary is hovered over to show it is clickable.

Lorem Ipsum...

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.

Sed ut perspiciatis...

Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam eaque ipsa, quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt, explicabo.

At vero eos et accusamus...

At vero eos et accusamus et iusto odio dignissimos ducimus, qui blanditiis praesentium voluptatum deleniti atque corrupti, quos dolores et quas molestias excepturi sint, obcaecati cupiditate non provident, similique sunt in culpa, qui officia deserunt mollitia animi,

The container div was given the id of "detailscmenu". The <details> tags were given the class of "dettestc" and the id of "dettestc1", "dettestc2", and "dettestc3". The CSS for this example is:

	#detailscmenu {
		position: relative; 
		width: 100%;
		height: 1em;
	}
	
	.dettestc { 
		display: inline-block; 
		position: absolute;
		top: 0;
		width: 100%;
		border: 2px solid blue;
	}
	
	.dettestc summary { 
		cursor: pointer;
		width: fit-content;
		border: 2px solid red;
	}
	
	.dettestc p {
		position: relative;
		left: 0;
		background-color: greenyellow;
	}
	
	#dettestc1 { left: 0; }
	#dettestc1 p { left: 0; }
	#dettestc2 { left: 140px; }
	#dettestc2 p { left: -140px; }
	#dettestc3 { left: 320px; }
	#dettestc3 p { left: -320px; }

Styling the <Summary> Tag Icon

The default arrow icon in the <summary> tag uses the list-style property. It can be removed by simply setting it's styling to "none", but the easiest way is to simply set the <summary> tag's display styling to "block".

Lorem Ipsum...

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.

The CSS to do the above is:

	.sumtestd { display:block; }

Alternatively, using the list-style property the following can be used:

	.sumtestd {list-style: none}
	.sumtestd::-webkit-details-marker {display: none; }

The problem with the above that there is now no indication at all that the element is clickable. The <details> tag is both tabbable and can be opened and closed using either the Enter key or Spacebar, but there are other visual clues that can be used such as changing the cursor on the <summary> tag to cursor: pointer; changing the color on mouse hover, underlining the text, using a tooltip, adding a border and others.

Suppose you want to use your own icons instead of the default. First of all remove the default icons as in the last example then use the ::before CSS selecor to insert your own. I use the up/down triangle in my current menus, so I'll use those here...

Lorem Ipsum...

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.

The CSS to do this is:

	.sumteste { display:block; }
	
	.detteste .sumteste::before { content:"\25BC "; }

	.detteste[open] .sumteste::before { content:"\25B2  "; }

Using the ::after pseudo-selector the position of the icon can be moved to after the summary text...

Lorem Ipsum...

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.

The CSS to do this is...

	.sumtestf { display:block; }
	
	.dettestf .sumtestf::after { content:"\25BC "; }

	.dettestf[open] .sumtestf::after { content:"\25B2  "; }

The JavaScript used to close the tags when a new one is opened is as used before.

<script type="text/javascript">
	document.querySelectorAll('.dettestc').forEach((D,_,A)=>{ D.ontoggle =_=>{ if(D.open) A.forEach(d =>{ if(d!=D) d.open=false })}
})
</script>

A Full Menu

A test of what can be done with the <details> and <summary> tags would be to reproduce the main menu for the pages on this site:

The HTML for the above menu is:

<div id="menubar">
	<details class="detmenu" id="detmenu1">
		<summary>All Sections</summary>
		<div class="submenu"><!--#include virtual="/inc/main_menu.htm" --></div>
	</details>
	<details class="detmenu" id="detmenu2">
		<summary>Web Section</summary>
		<div class="submenu"><!--#include virtual="/web/inc/web_menu.htm" --></div>
	</details>
</div>

The includes are just adding unordered lists on the server.

The CSS for it is:

#menubar {
	width: 100%;
	height: 1.5em;
	background-color: midnightblue;
	color: white;
	font-family: Arial, Helvetica, sans-serif;
	font-size: 1.2em;
	position: relative;
}

.detmenu {
	display:inline-block;
	position: absolute;
	width: 100%;
	padding-top: 0.2em;
}
	
.detmenu summary {
	cursor: pointer;
	width: fit-content;
	padding 0 0.5em;
}
	
.detmenu summary:hover, .detmenu summary:focus { color: cyan; }
	
.submenu {	
	position: relative;
	display: block;
	cursor: pointer;
	background-color: midnightblue;
}
	
#detmenu1 { left: .5em; }
#detmenu1 .submenu { left: -0.5em; }
#detmenu2 { left: 8em; }
#detmenu2 .submenu { left: -8em; }
	
.submenu a:hover, .submenu a:focus  { color: cyan; }
	
.submenu ul {
	column-count: 6;
	padding: 0.5em;
	margin-top: -20px;
}
 
.submenu li {
	list-style-type: none;
	display:block;
}
	
.submenu a {
	color: white;
	text-decoration: none;
}

The JavaScript for it is:

document.querySelectorAll('.detmenu').forEach((D,_,A)=>{ D.ontoggle =_=>{ if(D.open) A.forEach(d =>{ if(d!=D) d.open=false })}})

The above JavaScript came from Stack Overflow and may be too terse for maintainability, in which case one of the other snippets on the page can be used.

The number of columns in the submenus can be changed using media queries, for example:

@media screen and (max-width : 600px) {
	.submenu ul { column-count: 3; }
}

The menu will still work with JavaScript turned off, but because of the number of links, I made the submenus the full width of the div they are in and repositioned them to left. This means they overlay eachother so the uppermost must be closed to see the open ones underneath. For single list menu items with no repositioning of the submenus, this should not be a problem, it just means all the currently selected submenus will be seen.


Sources and Resources

The <details> Tag

<details>: The Details disclosure element - MDN Web Docs
Automatically close all the other <details> tags after opening a specific <details> tag - Stack Overflow
Can I use details - Browser support for details & summary elements
CSS Selector Reference - W3Schools
Focusable Elements - Browser Compatibility Table - A nice table showing which HTML elements are focusable and tabbable
HTML <details> Tag - W3Schools
The details and summary elements, again - Interesting article by Scott O'Hara discussing the accessibility of the details tag
The Details Element - W3C Working Draft
Using <details> for Menus and Dialogs is an Interesting Idea - CSS Tricks
UTF-8 Geometric Shapes - W3Schools

Accessibility Checkers

AccessiBe accessScan - Online accessibility checker
Accessible Web - Online accessibility checker
AChecker - Online accessibility checker
ADAScan βeta - Online accessibility checker
axe DevTools - Chrome Browser Extension accessibility checker
Experte Accessibility Check - Online accessibility checker
Intent Based Accessibility Checker - Online accessibility checker
WAVE - Chrome Browser Extension accessibility checker
Web Accessibility Evaluation Tools List - W3C Web Accessibility Initiative

<selectlist> & <selectmenu> Tag

Add customizable select element, currently <selectlist> - GitHub
Customizable <select> Element - Chrome Platform Status
Open UI's <selectlist> demos - Microsoft Edge Demos
Say Hello to selectmenu, a Fully Style-able select Element - CSS Tricks
Selectlist Element - Open UI
Styling 'select' elements for real - Microsoft Windows Blog