I'm building an interactive widget that consists in making a button list out of a list of HTML markups. To achieve that, the HTML markup is wrapped with a button-like component <div role="button" tabindex="0" aria-label="Action...">
. When clicking on the button, some script is executed.
I don't have control over that child HTML markup, and I want to prevent all other interactive elements from being interacted with. They should stay visible, though.
From the point of view of a mouse user, this can be achieved by setting pointer-events: none;
on all child elements.
From the point of view of a keyboard user, I need a way to prevent interactive elements from being interacted with.
In this example, the focus should go from the first div with tabindex="0" to the second div with tabindex="0", without focusing on the <a>
tag.
.focusable {
border: 1px solid blue;
margin: 10px;
padding: 10px;
}
.focusable > * {
pointer-events: none;
}
.focusable:hover {
background-color: lightgrey;
}
<div role="button" tabindex="0" class="focusable" aria-label="Action 0">
<div>Some html markup
<a href="#">Should not be focusable, but should be visible</a>
</div>
</div>
<div role="button" tabindex="0" class="focusable" aria-label="Action 1">
<div>Some html markup
<input type="text" placeholder="should not be focusable" />
</div>
</div>
One way I thought of achieving that is to set tabindex="-1"
on the child interactive elements. It will remove those from the tab order. However, it will not prevent them from being accessed programmatically, for example, from a screen reader links menu.
I wondered if there are other techniques to make all child elements of an element non-interactive. Especially something that can be applied on a wrapper, so there is no need to find all interactive elements and replace them.
The easiest solution is to give inert attribute to the first child element of the <div role="button">
. According to MDN:
Specifically, inert does the following:
- Prevents the click event from being fired when the user clicks on the element.
- Prevents the focus event from being raised by preventing the element from gaining focus.
- Hides the element and its content from assistive technologies by excluding them from the accessibility tree.
However browser support is not good, for example no support on Firefox.
For better compatibility the solution is to use:
aria-hidden="true"
: hides from accessibility treetabindex="-1"
: removes from tab navigationpointer-events: 'none'
: prevents pointer interaction