Skip to content

bug(mat-chip-option): MatChipOption's internal .mdc-evolution-chip__cell wrapper breaks NVDA focus mode for mat-chip-listbox (Chrome/Edge) #33604

Description

@InaTencu

Is this a regression?

  • Yes, this behavior used to work in the previous version

The previous version in which this bug was not present was

No response

Description

When a mat-chip-listbox with mat-chip-option children is navigated with NVDA in Chrome or Edge, NVDA never enters "focus mode" for the listbox, so arrow keys do nothing: Up/Down read the surrounding page text and Left/Right spell out the focused chip's label character by character. Focus never actually moves between chip options via the keyboard — only Tab (which exits the listbox) or a mouse click works. This reproduces on the official chips demo at https://material.angular.dev/components/chips/examples#chips-stacked. Firefox + NVDA is unaffected — arrow key navigation works there.

Confirmed reproducible across every Angular Material version from v15 through v22.

Root cause

MatChipOption's compiled template renders:

<mat-chip-option role="presentation">           <!-- host: MatChipOption.ngOnInit() forces role="presentation" -->
  <span class="mdc-evolution-chip__cell mdc-evolution-chip__cell--primary">  <!-- no role at all -->
    <button matChipAction role="option"></button>
  </span>
</mat-chip-option>

Only one of those two wrapper layers is actually a problem: the outer role="presentation" host is exactly what the ARIA spec expects to be transparent when resolving an element's required context role (here, option's required listbox ancestor), and on its own it doesn't break anything. The .mdc-evolution-chip__cell span is the one non-transparent layer — it has no role at all, and Chromium fails to see through it, so the option no longer reads as a descendant of the listbox.

Isolated via a minimal structural repro:

  • role="option" directly under role="listbox" — works.
  • role="option" under a single role="presentation" wrapper — still works.
  • role="option" under a plain, roleless <span> (itself inside the role="presentation" host) — breaks. This is exactly MatChipOption's real shape.
  • Giving that same intermediate <span> an explicit role="presentation" too (so the chain becomes presentation → presentation → option instead of presentation → generic → option) restores focus mode.

.mdc-evolution-chip__cell carries no semantic meaning — it's a layout-only wrapper — so marking it role="presentation" in the MatChip/MatChipOption/MatChipRow templates should fix this.

Reproduction

  1. Open the chips listbox demo (or any mat-chip-listbox with several mat-chip-option children).
  2. Start NVDA on Windows, using Chrome or Edge.
  3. Tab focus into the chip listbox.
  4. Press the Left/Right (or Up/Down) arrow keys.

Expected Behavior

NVDA enters focus mode and forwards arrow keys to the listbox, moving real focus between chip options — same as Firefox + NVDA today.

Actual Behavior

NVDA stays in browse mode; arrow keys are consumed by NVDA instead of reaching the listbox, and focus never moves between chips via keyboard.

Environment

  • Angular Material: reproducible on v15 through v22 (tested)
  • Browsers affected: Chrome, Edge (Chromium-based)
  • Browser unaffected: Firefox
  • Screen reader: NVDA
  • OS: Windows

Metadata

Metadata

Assignees

No one assigned

    Labels

    area: material/chipsgemini-triagedLabel noting that an issue has been triaged by geminineeds triageThis issue needs to be triaged by the team

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions