Use the inert attribute to prevent unintended user interaction

Web design is all about making efficient use of the available space. You don't want to clutter the screen with too much content. This is the reason for common patterns like slide-in submenus, expansion panels, popups or dialogs.

Often, these elements are implemented as custom widgets with an insufficient hidden state. They use CSS code like opacity: 0 or position: absolute; left: -10000px to hide the content only visually. But users can still access the content with the keyboard or assistive technologies. What can we do about it?

Sloth hanging on tree branch. Photo: © Roxanne Minnish / pexels.com

You can use the HTML attribute inert to prevent any interaction with hidden content. A kind of digital sloth, so to say. Let's take a closer look at the attribute that is now supported by all major browsers.

How the inert attribute works

The inert property is a global HTML attribute that tells the browser to prevent any user interaction with a specific section of content. The HTML specification states:

The inert attribute is a boolean attribute that indicates, by its presence, that the element and all its flat tree descendants [...] are to be made inert by the user agent.

This means that all user input events for the element and its descendants are ignored, including focus events and events from assistive technologies.

For example: Let's say you place a registration form off-screen and let it slide into view when the user presses a certain button. Adding inert to the <form> element ensures that a keyboard user cannot accidentally interact with the form elements while they're off-screen. The content will also be hidden from screen reader users.

The native <dialog> element also makes use of this. When you open a modal dialog with .showModal(), the browser will automatically render all other content inert. Find out more in my blog post “Why you should use the Native Dialog Element”.

Use Case: Animated Navigation Menu

I've created a demo for an animated navigation menu that uses the inert attribute for its hidden submenus. It works well for keyboard and screen reader users:

The navigation menu is structured as an unordered list inside a nav element. The HTML code for a menu option and its hidden submenu looks as follows:

<button type="button" aria-expanded="false" aria-controls="sub_menu_research"> Research </button> <div id="sub_menu_research" class="subMenu" inert> <ul> <li><a href="/black-holes">Black Holes</a></li> <li><a href="/climate-change">Climate Change</a></li> <li><a href="/modern-way-of-work">Modern Way of Work</a></li> </ul> </div>

In my CSS code, I reference the inert attribute to also visually hide the submenu:

.subMenu { overflow: hidden; } .subMenu[inert] > ul { transform: translateY(-100%); }

When the menu option is activated, the inert attribute is removed and the submenu slides into view:

.subMenu:not([inert]) > ul { transform: translateY(0); }

The creation of the slide animation is pretty easy and straightforward using the transition CSS property:

.subMenu > ul { transition: transform 0.4s ease-in-out; }

You can view the complete source code here.

Wouldn't display: none do the job?

Some of you might be thinking: “Why should I use the inert attribute? I can simply hide stuff with display: none, duh!” You're right. When you apply the CSS property display: none to an element, it won't be rendered by the browser and is hidden from assistive technologies. The downside: You won't be able to animate the element any more.

Using the inert attribute gives you more flexibility. You can let your content fade in and out, slide into view or create any sophisticated animation you can think of. Also, you'll want to use the attribute for content that is visible but should not be interacted with. For example, the partially visible previous and next slide in a carousel widget.

Browser Support

Firefox finally added support for inert in version 112. This means that all major browsers support the attribute now.

Yay! Let's go and build cool stuff with it.

Posted on