Skip to content

[2.x] fix: tell assistive technology which dropdown option is selected - #4900

Merged
imorland merged 1 commit into
2.xfrom
im/select-dropdown-aria-current
Aug 5, 2026
Merged

[2.x] fix: tell assistive technology which dropdown option is selected#4900
imorland merged 1 commit into
2.xfrom
im/select-dropdown-aria-current

Conversation

@imorland

@imorland imorland commented Aug 5, 2026

Copy link
Copy Markdown
Member

Fixes #3362.

A SelectDropdown shows which option is in effect two ways — a class on the item, and the toggle button borrowing that option's label. Neither reaches a screen reader, so moving through the menu announces an undifferentiated list of options with no indication of which one is active.

The selected item now carries aria-current="true".

Why aria-current and not aria-selected

The issue asks for aria-selected, but that attribute is only valid on elements with role option, tab, row, gridcell or treeitem. The menu is a plain <ul> of <li> wrapping buttons:

getMenu(items) {
  return <ul className={'Dropdown-menu dropdown-menu ' + this.attrs.menuClassName}>{items}</ul>;
}

with no role declared in Dropdown, SelectDropdown or Select. Adding aria-selected there would be ignored by assistive tech at best, and flagged as invalid by axe/Lighthouse at worst.

Giving the menu role="listbox" and its items role="option" would make it valid, but that is a contract — it commits us to arrow-key navigation and aria-activedescendant, which is a much bigger piece of work and belongs with #3361 and the rest of the keyboard-navigation issues. aria-current is valid on any element and states what is actually meant: the current item within a set.

Unselected items are left without the attribute rather than given "false". Only one item can be current, so the absence carries the meaning — and Mithril omits an attribute set to false regardless.

Scoping

The tidier place would have been listItems, which already works out which item is active and adds the active class. It is scoped to SelectDropdown instead because that helper wraps every list in Flarum, and the only component implementing isActive is LinkButton — which is route-based. Nav items are genuinely navigation and want aria-current="page", so marking them "true" would be wrong.

Tests

Three added to the existing SelectDropdown.test.ts:

  • the selected option is marked — exactly one [aria-current="true"], and it is the right one
  • unselected options are not marked — guards against applying it to everything
  • nothing is marked when no option is selected — passes before this change as well as after; it is the guard against over-application

I checked the first two fail without the change rather than assuming it.

All integration suites green: 49 suites, 162 tests. check-typings clean.

To try it

Open a select dropdown — the sort dropdown on the discussion index is the clearest — and inspect the menu. The current option's <li> should carry aria-current="true" and the others should have no such attribute.

A `SelectDropdown` showed which option was in effect two ways, neither of
which reaches a screen reader: a class on the item, and the toggle button
borrowing that option's label. Moving through the menu announced an
undifferentiated list of options.

The selected item now carries `aria-current="true"`.

`aria-current` rather than the `aria-selected` the issue asks for: that
attribute is only valid on roles this menu does not claim — `option`, `tab`,
`row`, `gridcell`, `treeitem` — and the menu is a plain `ul` of `li` wrapping
buttons, with no role declared. Claiming those roles would mean honouring the
whole listbox keyboard contract, which is a much larger piece of work and
belongs with the keyboard-navigation issues. `aria-current` is valid on any
element and says what is meant: the current item within a set.

Unselected items are left without the attribute rather than given `"false"`.
Only one item can be current, so its absence carries the meaning — and Mithril
omits an attribute set to `false` anyway.

Scoped to `SelectDropdown` rather than `listItems`, which would have been the
tidier place since it already works out which item is active. That helper
wraps every list in Flarum, and the only component implementing `isActive` is
`LinkButton`, which is route-based — nav items want `aria-current="page"`, so
marking them `"true"` would be wrong.
@imorland
imorland requested a review from a team as a code owner August 5, 2026 14:35
@imorland imorland added the type/accessibility Issues relating to accessibility (keyboard navigation, screenreaders, text contrast, etc.) label Aug 5, 2026
@imorland imorland added this to the 2.0.0-rc.6 milestone Aug 5, 2026
@imorland
imorland merged commit 2d06048 into 2.x Aug 5, 2026
24 checks passed
@imorland
imorland deleted the im/select-dropdown-aria-current branch August 5, 2026 14:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

type/accessibility Issues relating to accessibility (keyboard navigation, screenreaders, text contrast, etc.)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[A11Y] Add missing aria-selected attribute to selected dropdown items

1 participant