Slide-out navigation is everywhere. Sometimes called drawers or slide-out menus, they allow for more content to be available without taking up extra space on the screen. For example, some hamburger “menus” slide in from the side of the screen and contain navigation links. To ensure that keyboard users have full access to your site, it’s important to manage focus. Here are three situations to avoid when it comes to slide-out navigations:
- Focus moves into the navigation even when it’s closed
- Focus doesn’t move directly into the open navigation
- Slide-out navigation stays open while focus is on content behind it
We’ll take a look at each of these and provide possible solutions.
Note: This example is for slide-out navigation, not for application menus. It does not follow the ARIA menu pattern. For more information on the distinction, refer to Inclusive Components: Menus and Menu Buttons.
Slide-out navigation refers to content that slides in from the side of the screen. In the video below, the slide-out navigation slides in from the left side after the hamburger menu button is clicked. To try it out yourself, take a look at our codepen.
Focus moves into the navigation even when it’s closed
It is important for sighted keyboard-only users to be able to see where focus is on the page. When a user presses the Tab key, for instance, focus moves from one interactive element to the next. Visually, the element that is focused should be clearly highlighted. For example, a border can be added around the element when it’s focused.
Often, the links and other interactive elements in a slide-out navigation are still focusable even when the menu is closed. This can be a confusing and frustrating experience for users. Nothing visually indicates where focus is on the page.
The video below shows a user tabbing from the hamburger menu button to the links in the main section of the page. There are several Tab presses for which there is no visible focus. This is because the user must tab through all the links in the closed slide-out navigation before reaching the links that are visible on the page.
Hiding the slide-out navigation
Using CSS, we can hide the slide-out navigation when it’s closed. This will hide it visually, hide the content from screen reader users (until the slide out is opened), and remove focusable elements from the tab order. Using display:none
can cause problems when animating the content. Instead we’ll use visibility:hidden
.
In the video below, the slide-out navigation has been hidden using visibility:hidden
. Focus moves straight from the hamburger menu button to the links on the main part of the page. When the navigation is open, visibility is restored (visibility:visible
). The links in the slide-out navigation are back in the tab order.
Let’s take a look at the code we need to accomplish this. Here is the HTML:
<nav>
<button type="button" id="hamburger-menu" class="open-nav-btn" aria-label="open navigation" aria-controls="link-list" aria-expanded="false">☰</button>
<div id="slide-nav" class="slide-content">
<button type="button" id="close" class="close-btn" aria-label="close navigation">×</button>
<ul id="link-list">
<li><a href="...">Services</a></li>
<li><a href="...">Programs</a>
<li><a href="...">Blog</a></li>
<li><a href="...">About Us</a></li>
<li><a href="...">Contact</a></li>
</ul>
</div>
</nav>
Note: Generally, screen reader users not on mobile devices are also keyboard-only users. This example places the hamburger menu button within the <nav>
element. This allows screen reader users to navigate directly to the navigation landmark. If the entire <nav>
is hidden with visibility:hidden
, there will be no navigation landmark for screen reader users to navigate to. Use a <div>
instead of <nav>
for the slide-out content itself. This strategy borrows from Inclusive Components: Menus and Menu Buttons.
On page load, the slide-out content should be hidden. Here’s the CSS we used for this example:
.slide-content {
visibility: hidden;
width: 0;
...
}
When the slide-out navigation opens, add an active class to it. The active class will slide the navigation into view. This code will change with later focus management considerations. All changes will be discussed below.
Here’s the JavaScript (written in jQuery):
function openNav() {
$sideNav.addClass("active");
}
And here’s the CSS:
.active {
visibility: visible;
width: 250px;
}
Focus doesn’t move directly into the open navigation
It can be confusing for sighted keyboard users if focus order does not follow the visual order of the page. For English-language sites, or any site written in a left-to-right script, focus should move from left to right and top to bottom. Focus should also move into new content when it appears.
Users expect that once they press the hamburger menu button, focus will move into the slide-out content. Focus should move to either the first link or the close button.
The location of the HTML code for the slide-out content is important. When a user presses the Tab key to navigate through content, the focus order follows the order of the source code. Placing the code for the slide-out content after the main content changes the focus order. The user will have to tab through all other active elements within the main content before reaching the visible navigation links. When the slide-out navigation closes, focus will be at the end of the main content. Keyboard users will have to navigate all the way back to the top of the page to continue where they left off before opening the navigation.
The video below demonstrates how focus moves past the slide-out content to links in the main content of the page. Focus only arrives at the slide-out navigation after the main content. When the slide out closes, the user moves focus back up to the hamburger menu button from the bottom of the page. This requires moving focus back through all focusable elements in the main content.
To fix the focus order, you will need to use JavaScript. When the slide-out navigation opens, focus should move to either the first link in the list or to the close button. When the slide-out navigation closes, focus should move back to the hamburger menu button. This ensures that the focus order matches the visual order and users’ expectations.
How can you move focus to an element that is hidden from view? You will either have to wait until the slide-out animation is complete, or you will need to make the content available before the animation is complete. We recommend the second option. Waiting for the animation to complete leads to a more confusing experience for screen reader users.
Make the content available for focus before the animation is complete
Make sure the slide content transition is specific to width only.
.slide-content {
transition: width 0.5s;
...
}
Separate visibility from the active class.
.visible {
visibility: visible;
}
.active {
width: 250px;
}
When the slide-out navigation opens, add the visible and active classes. Send focus to the close button or first link.
function openNav() {
$slideNav.addClass("visible active");
setTimeout(function() {
$("#close").focus()
}, 1);
...
}
When the slide-out navigation closes, remove the active class and send focus back to the hamburger menu button. You will want to wait until the animation is over before removing the visible class.
function closeNav(e) {
...
$slideNav.removeClass("active");
setTimeout(function() {
$hamburgerMenuBtn.focus()
}, 1);
setTimeout(function() {
$slideNav.removeClass("visible")
}, 501);
}
Slide-out navigation stays open while focus is on content behind it
This situation is a little more complex: if a user tabs through all options in the slide-out navigation, when the user tabs again their focus is now in the main part of the page. Some of this content is visually obscured by the open slide-out navigation.
In the video below, focus moves through the slide-out content and into the main section of the page. The open navigation covers the content below it. While the links receive focus, there is no way to see which links are in focus.
There are many approaches to ensure that main content is not covered by slide-out content. Which is best depends on the context of the content. When in doubt, user testing is always the best way to decide which method works best for users. Below is one method that we recommend in many cases.
Keep keyboard focus in the slide-out navigation until it’s closed
For this method of focus management, focus does not leave the slide-out navigation. Instead, event listeners are set to listen for the Tab key and the Shift and Tab key together.
- When the user is on the last focusable element in the menu and presses the Tab key, focus moves to the first focusable element in the menu.
- When the user is moving backward through the tab order using the Shift and Tab keys, the opposite happens. When the user presses Shift and Tab on the first focusable element, focus moves to the last focusable element in the menu.
The video below shows this in action.
Try it for yourself!
See the Pen Slide-Out Navigation by Alicia Evans (@unleashalicia) on CodePen.
Now let’s look at the code. You can view the full code example in our codepen.
For JavaScript, we are using ECMAScript 5 (ES5) and jQuery.
First, let’s assign our variables. We’ll want to assign a variable to the slide out that appears when the user clicks the hamburger menu button and for the hamburger menu button itself.
var $slideNav = $("#slide-nav"),
$hamburgerMenuBtn = $("#hamburger-menu");
Next we want to collect an array of all focusable elements within the slide-out navigation.
$focusableInNav = $('#slide-nav button, #slide-nav [href], #slide-nav input, #slide-nav select, #slide-nav textarea, #slide-nav [tabindex]:not([tabindex="-1"])');
From this array, we can grab the first and last element. This will give us the first focusable element and the last focusable element of the slide-out navigation.
var $firstFocusableElement = $focusableInNav.first(),
$lastFocusableElement = $focusableInNav.last();
Now that our variables are defined, we can add our event listeners.
function addEventListeners() {
...
$firstFocusableElement.on("keydown", moveFocusToBottom);
$lastFocusableElement.on("keydown", moveFocusToTop);
}
Now we can handle focus when the slide out is open. Let’s start with the first case: if the user is on the last focusable element and presses the Tab key, move focus to the first focusable element.
First, check on which keydown
event brought you here. We are looking for the Tab key without the Shift key.
Then, prevent the default behavior: don’t move focus to the main section. Instead, send focus to the first focusable element in the slide-out navigation - the close button.
function moveFocusToTop(e) {
if (e.key === "Tab" && !e.shiftKey) {
e.preventDefault();
$firstFocusableElement.focus();
}
}
The next function handles the case of a user pressing Shift and Tab to move backward through the slide-out navigation.
First check that the keydown
event is from the Tab and Shift key pressed together. Then, don’t move focus to the hamburger menu button. Instead, move focus to the last focusable element in the slide-out navigation.
function moveFocusToBottom(e) {
if (e.key === "Tab" && e.shiftKey) {
e.preventDefault();
$lastFocusableElement.focus()
}
}
Don’t forget the Escape Key!
Be kind to your keyboard-only users. Let them exit your slide-out content quickly with the Escape key. Add an event listener on the slide-out navigation that will listen for a keyup
event.
$slideNav.on("keyup", closeNav);
In your closeNav
function, add a check for keyup
events. Exit the function if any key was pressed except for the Escape key. The closeNav
function closes the slide-out navigation and returns focus to the hamburger menu button.
function closeNav(e) {
if (e.type === "keyup" && e.key !== "Escape") {
return;
}
...
}
Conclusion
It is important to consider focus management when building slide-out navigations. There are many ways to ensure that slide outs are keyboard accessible.
In the end, it is important that:
- Focus does not move into closed slide-out content
- Focus moves into the content when it’s open
- Focus is managed when the user reaches either end of the menu
Keeping these things in mind allows for more people to access and enjoy your site.