Skip to content

a11y: Dropdown toggle announces aria-haspopup="true" but the popup has no menu semantics #4403

Description

@wittjeff

Context

Found during the 2026 Axim-commissioned accessibility audit of Paragon, while documenting Dropdown against the APG menu button pattern.

Current behavior

Paragon's Dropdown wraps React-Bootstrap 1.6.5. The rendered toggle is a <button> with aria-haspopup="true" and aria-expanded, but the popup (Dropdown.Menu) renders with no role="menu", and items render as a.dropdown-item/buttons with no role="menuitem" (React-Bootstrap's intentional avoidance of ARIA menu semantics, inherited from Bootstrap).

Impact

aria-haspopup="true" maps to aria-haspopup="menu": screen readers announce the toggle as a "menu button" and set user expectations of menu semantics (menu role, menuitem count/position, first-item focus) that the popup does not expose. The mismatch is confusing rather than strictly broken. WCAG mapping: 4.1.2 Name, Role, Value.

Additionally, Dropdown.test.jsx currently has no keyboard or ARIA assertions (open/close behavior only), so neither resolution direction is guarded by tests.

Options

  1. Align with disclosure semantics (smaller change): remove/override aria-haspopup so the toggle announces as a plain expandable button — consistent with what the popup actually is (a list of links/buttons).
  2. Adopt full APG menu button semantics: add role="menu"/role="menuitem" and the corresponding keyboard contract. Higher effort and only appropriate for action menus, not navigation.

Option 1 is likely correct for most Paragon usages; either way the decision should be recorded in the component's Accessibility docs.

References

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions