angular / angular/components

bug(a11y): FocusTrap doesn't match browser/spec tab order in relation to Shadow DOM

Open
#32,265 0 comments 0 reactions 0 assignees View on GitHub
area: cdk/a11y P3
Dominant language
TypeScript
Stars
25k
Forks
6.8k
Avg merge
1d 8h
Merged PRs (30d)
91

Description

_EDIT: Removed the regression questions, it's not a regression_

### Description

A project I work with uses a component library based on https://lit.dev with `CUSTOM_ELEMENTS_SCHEMA`. They sometimes have regular, tabbable elements (``, ``) in their Shadow DOM and participate in the browser tab order as expected.

However, the CDK `FocusTrap` machinery and the `_getFirstTabbableElement` / `_getLastTabbableElement` don't quite consider enough of the [sequential focus navigation]. That means that focus trapping in a dialog only works it there's at least one *focusable area* not in a Shadow DOM.

For performance reason, I don't think it's necessary to build up the full [sequential focus navigation order]. It'd probably be sufficient to use the [`"DOM"` selection mechanism](https://html.spec.whatwg.org/multipage/interaction.html#selection-mechanism-dom) i.e. find the first/last [suitable sequentially focusable area] element in [shadow including tree order] (host - shadow dom - light dom).

[shadow including tree order]: https://dom.spec.whatwg.org/#concept-shadow-including-tree-order
[suitable sequentially focusable area]: https://html.spec.whatwg.org/multipage/interaction.html#suitable-sequentially-focusable-area
[sequential navigation search algorithm]: https://html.spec.whatwg.org/multipage/interaction.html#sequential-navigation-search-algorithm
[sequential focus navigation]: https://html.spec.whatwg.org/multipage/interaction.html#sequential-focus-navigation
[sequential focus navigation order]: https://html.spec.whatwg.org/multipage/interaction.html#sequential-focus-navigation-order

### Reproduction

StackBlitz link: https://stackblitz.com/edit/components-issue-starter-2e9thbl6?file=src%2Fmain.ts
Steps to reproduce:
1. Click in the preview window, preferably somewhere in the top part of the red area.
2. Tab to see the focus (outline) on the button in the red area
3. Tab to see the focus on the hidden trap element
4. Tab to see the focus (outline) on the button in the blue area
5. Keep Tabbing to see the focus actually get trapped

### Expected Behavior

The focus should remain trapped in the red area

### Actual Behavior

The focus moves past the red area, to an invisible item and then only gets trapped in the blue area.

### Environment

- Angular: 19, 20
- CDK/Material: 19, 20
- Browser(s): Edge, Firefox
- Operating System (e.g. Windows, macOS, Ubuntu): Windows 11 Enterprise

Contributor guide

Open the contributing guide

Research direction

Start with the CDK FocusTrap machinery and its _getFirstTabbableElement/_getLastTabbableElement methods, then reproduce the behavior using the linked StackBlitz example. Compare the traversal with shadow-including tree order and verify that focus remains within the red trapped area instead of moving through the hidden trap element.

Written by the indexing model from the issue text.

Assessment

Tech stack
angular, typescript
Domain
accessibility, frontend
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.