dequelabs / dequelabs/axe-core

False positive: scrollable-region-focusable on menus with programmatic keyboard focus

Open
#5,363 0 comments 0 reactions 0 assignees View on GitHub
fix high rules scrollable-region-focusable support
Dominant language
JavaScript
Stars
7.5k
Forks
933
Avg merge
2d 23h
Merged PRs (30d)
17

Description

### Product

axe-core

### Product Version

4.13.0 (develop)

### Latest Version

- [x] I have tested the issue with the latest version of the product

### Issue Description

#### Expectation

`scrollable-region-focusable` should pass. The list is keyboard accessible: activating the Products button (or ArrowDown on it) moves focus to the first item, and arrow keys move between items.

#### Actual

axe reports a violation on `#menu` (`Element should have focusable content` / `Element should be focusable`).

#### How to Reproduce

```html

#menu {
max-height: 6em;
overflow-y: auto;
width: 12em;
margin: 0;
padding: 0;
border: 1px solid;
list-style: none;
}
#menu button {
display: block;
width: 100%;
text-align: left;
}

Products


  • Keyboards

  • Mice

  • Monitors

  • Headsets

  • Webcams

  • Microphones

  • Docking stations

  • Cables

const menubutton = document.getElementById('menubutton');
const menu = document.getElementById('menu');
const menuitems = [...menu.querySelectorAll('button')];

function setExpanded(isExpanded) {
menubutton.setAttribute('aria-expanded', String(isExpanded));
menu.hidden = !isExpanded;
}

menubutton.addEventListener('click', () => {
const isExpanded = menubutton.getAttribute('aria-expanded') === 'true';
setExpanded(!isExpanded);
if (!isExpanded) {
menuitems[0].focus();
}
});

menubutton.addEventListener('keydown', event => {
if (event.key !== 'ArrowDown') {
return;
}
event.preventDefault();
setExpanded(true);
menuitems[0].focus();
});

menu.addEventListener('keydown', event => {
const index = menuitems.indexOf(event.target);
const offset = { ArrowDown: 1, ArrowUp: -1 }[event.key];
if (index === -1 || !offset) {
return;
}
event.preventDefault();
menuitems[(index + offset + menuitems.length) % menuitems.length].focus();
});

```

#### Additional context

Customer mega menu. Items stay `tabindex="-1"` and are focused by script. `tabindex="-1"` on the `ul` is only there to stop Chrome from focusing the scroll container.

Contributor guide

Open the contributing guide

Research direction

Start by reproducing the supplied menu example and inspect the scrollable-region-focusable rule, focusing on how programmatically focused menu items and the tabindex="-1" scroll container are evaluated. Add a regression test for this markup, then verify the menu no longer reports a violation while existing scrollable-region checks still behave as expected.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript
Domain
accessibility, testing-qa
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
65/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.