Skip to content

fix(material/chips): correct focus management on chip destruction#33329

Merged
crisbeto merged 4 commits into
angular:mainfrom
zsheikh-eng:fix-chip-focus-bug
Jun 16, 2026
Merged

fix(material/chips): correct focus management on chip destruction#33329
crisbeto merged 4 commits into
angular:mainfrom
zsheikh-eng:fix-chip-focus-bug

Conversation

@zsheikh-eng

@zsheikh-eng zsheikh-eng commented Jun 1, 2026

Copy link
Copy Markdown
Contributor

Fixes #14345

Description

The Bug:
When a chip is removed from MatChipSet or MatChipGrid, keyboard navigation (like using Shift+Tab or arrow keys) breaks upon subsequent interactions. This happens because the internal FocusKeyManager retains a stale reference to the deleted chip if the focus leaves the chip container (e.g., when the list becomes empty or focus returns to the input box). This stale reference traps keyboard focus or causes it to drop to the document body, failing standard focus order requirements (WCAG 2.1 Success Criterion 2.4.3).

The Fix:
The solution is to preserve standard browser focus redirection while explicitly cleaning up staleReferences when focus exits the chip context. This PR:

Un-privatizes the redirection logic (_lastDestroyedFocusedChipIndex and _redirectDestroyedChipFocus) to protected in the base MatChipSet class.

Allows MatChipGrid to override this behavior, call super._redirectDestroyedChipFocus() to preserve deterministic browser focus moves, and perform a silent cleanup using updateActiveItem(-1) when navigation leaves the chip set.

Why this path?

Deterministic Focus: It relies on the superclass redirection to maintain standard browser focus moves (refocusing the input or next chip) that downstream applications and consuming components expect.

Cleanup without Hijacking: The silent cleanup ensures the FocusKeyManager is reset safely without aggressively forcing a browser focus event or stealing focus from adjacent input fields.

Testing:

Added unit tests to chip-grid.spec.ts asserting that focus redirects correctly to the next chip upon deletion, and that the internal state is safely reset when the last focused chip is destroyed.

Un-privatized _redirectDestroyedChipFocus to allow MatChipGrid to override the aggressive focus-stealing behavior with a silent updateActiveItem call, respecting downstream layout stability.

Fixes angular#14345
@pullapprove pullapprove Bot requested review from andrewseguin and ok7sai June 16, 2026 05:16
@crisbeto crisbeto added action: merge The PR is ready for merge by the caretaker target: patch This PR is targeted for the next patch release labels Jun 16, 2026
@crisbeto crisbeto merged commit e49f127 into angular:main Jun 16, 2026
13 of 16 checks passed
@crisbeto

Copy link
Copy Markdown
Member

This PR was merged into the repository. The changes were merged into the following branches:

crisbeto pushed a commit that referenced this pull request Jun 16, 2026
…3329)

* fix(material/chips): correct focus management on chip destruction

Un-privatized _redirectDestroyedChipFocus to allow MatChipGrid to override the aggressive focus-stealing behavior with a silent updateActiveItem call, respecting downstream layout stability.

Fixes #14345

* Update chip-grid.ts

* Update chip-grid.spec.ts

* Update chip.ts

(cherry picked from commit e49f127)
crisbeto added a commit to crisbeto/material2 that referenced this pull request Jun 16, 2026
Comments out a test that started failing after angular#33329.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

action: merge The PR is ready for merge by the caretaker area: material/chips target: patch This PR is targeted for the next patch release

Projects

None yet

Development

Successfully merging this pull request may close these issues.

CDK: ListKeyManager activeItem has incorrect reference after QueryList changes

2 participants