Creating an accessible header dropdown menu example

A step by step guide about of how to create header dropdown menus that are fully accessible

Step 1. Create a simple html structure with basic keyboard and mouse navigation

It is of best practice to always code with accessibility in mind from the start. The code development mantra of "Mobile first" should be "Mobile and accessible first". With this principle, you will create better html semantics that will also cause less css customizations headaches when you will try to test and validate the menu's accessibility.

In this step, we make sure that the code is usable by mean of keyboard or mouse. This takes care of the possible mechanical ways to interact with the menu component (with hands or other body movements). It is a great accessibility milestone but we will also need to make sure that the menu is also comprehensible for the visually impaired.

What makes it possible today to do a fully keyboard navigational menu is the recent css pseudo-property :focus-within. Without it, the focus would jump to the other parent menu item instead of giving focus to its child items. Make sure that you still don't need to support IE if using it (see canIUse). Otherwise there is a javascript pollyfill available.

        
            <nav>
                <ul>
                    <li>
                        <a href="../generic.html">Home</a>
                    </li>
                    <li>
                        <a href="../generic.html">Services</a>
                        <ul>
                            <li><a href="">Service 1</a></li>
                            <li><a href="">Service 2</a></li>
                            <li><a href="">Service 3</a></li>
                            <li><a href="">Service 4</a></li>
                            </ul>
                    </li>
                    <li>
                        <a href="../generic.html">About</a>
                        <ul data-test="true" aria-hidden="true" role="menu" class="">
                            <li><a href="">Our mission</a></li>
                            <li><a href="">History</a></li>
                            <li><a href="">Our people</a></li>
                            <li><a href="">Careers</a></li>
                        </ul>
                    </li>
                    <li>
                        <a href="../generic.html">Contact us</a>
                    </li>
                </ul>
            </nav>
        

    

        
            nav li {
                display: inline-block;
                position: relative;
                padding: 8px 16px;
            }

            nav li ul {
                display: none;
                position: absolute;
                left: 0;
                top: 0;
                min-width: 8em;
                padding:0;
                box-sizing: border-box;
            }

            nav li a:focus + ul,
            nav li a:hover + ul,
            nav li:focus-within ul,
            nav li ul:hover {
                top: 32px;
                display: block;
                border: solid 1px #ccc;
            }

            nav li ul li {
                display: block;
            }

            nav a {
                text-decoration: none;
            }
        
    

Step 2. Optimize the menu for screenreaders

This step is where we want to consider the use of Aria properties and labels. The menu appears and interacts the same by means of mouse or keyboard. We will, however, add some aria html markers so that screenreaders can read how it is organized.

There is often confusion that aria properties will help with the mechanical way of interacting. But they simply are html markers that provide more details to screenreader users about how items on a page are structured and organized.

        
                <nav role="navigation" aria-label="Main menu">
                    <ul role="menubar" aria-hidden="false">
                        <li role="menuitem" aria-haspopup="true">
                            <a href="../generic.html">Home</a>
                        </li>
                        <li role="menuitem" aria-haspopup="true">
                            <a href="../generic.html">Services</a>
                            <ul data-test="true" aria-hidden="true" role="menu" class="">
                                <li role="menuitem"><a href="">Service 1</a></li>
                                <li role="menuitem"><a href="">Service 2</a></li>
                                <li role="menuitem"><a href="">Service 3</a></li>
                                <li role="menuitem"><a href="">Service 4</a></li>
                                </ul>
                        </li>
                        <li role="menuitem" aria-haspopup="true">
                            <a href="../generic.html">About</a>
                            <ul data-test="true" aria-hidden="true" role="menu" class="">
                                <li role="menuitem"><a href="">Our mission</a></li>
                                <li role="menuitem"><a href="">History</a></li>
                                <li role="menuitem"><a href="">Our people</a></li>
                                <li role="menuitem"><a href="">Careers</a></li>
                            </ul>
                        </li>
                        <li role="menuitem" aria-haspopup="true">
                            <a href="../generic.html">Contact us</a>
                        </li>
                    </ul>
                </nav>
        
    

At this point, congratulate yourself because you've just made a fully html & css-only accessible menu. You could therorically stop the process here and your menu would meet the accessibility standards. However, there are still things that can be done to enhance the keyboard usage experience.

Step 3. Add extra keyboard interaction functionalities

This step is theorically optional but highly recommended for the user experience.

As mentionned, the first two step should have already made the menu fully accessible in terms of being able to use it with most disabilities. In this 3rd step however, we will enhance the keyboard user experience with some javascript.

One thing that could be annoying for example is that a keyboard nav user would need to go through all the sub menus when tabbing in the forward direction. Yes, it is accessible in terms of capability to focus on every links, but the UX could be better enhanced by decoupling the focus and hover behaviors. So the keyboard nav user could simply select the parent menu item without opening its sub-menu while leaving the hooving behavior as is.

Doing this, we can also add the aria-expanded property to indicate if the submenu is opened or not. The value would need to be toggled with javascript.

More details coming soon...

Last updated: March 11th 2021.