-
Notifications
You must be signed in to change notification settings - Fork 6.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix(focus-trap): not attaching correctly if element is not in the DOM on init #7665
fix(focus-trap): not attaching correctly if element is not in the DOM on init #7665
Conversation
0a63b61
to
2a8943b
Compare
src/cdk/a11y/focus-trap.ts
Outdated
// immediately, keep trying until it is. | ||
if (!this.focusTrap.hasAttached()) { | ||
this.focusTrap.attachAnchors(); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add a unit test for this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had a hard time putting together a unit test that would fail as we expect it to. The only way I got the issue to happen at runtime was using a focus trap as the content of a select which has a complicated setup around it. I tried throwing a portal into the unit test, but it still worked.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I ran into the issue with a setup like
<ng-template cdkConnectedOverlay>
<div cdkTrapFocus>...</div>
</ng-template>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That doesn't seem to work either. During the test the focus trap still manages to find a parent node which allows it to attach (the <div id="root0">
in particular which AFAIK is the Karma root element), whereas in the demo app it doesn't, For reference, here's what the test component looks like:
@Component({
template: `
<button cdkOverlayOrigin #origin="cdkOverlayOrigin">I'm the origin</button>
<ng-template cdkConnectedOverlay [open]="isOpen" [origin]="origin">
<div cdkTrapFocus><button>I'm trapped!</button></div>
</ng-template>
`
})
class FocusTrapInOverlay {
isOpen = false;
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The whole setup where it happened consistently was:
<ng-template
cdkConnectedOverlay
[cdkConnectedOverlayOrigin]="trigger"
[cdkConnectedOverlayOpen]="isOpen">
<div cdkTrapFocus class="color-picker"
role="dialog" aria-label="Color picker">
<div role="listbox" tabindex="0" aria-label="Select a color"
(keydown)="keydownHandler($event)">
<div *ngFor="let color of colors; index as i"
role="option"
[style.background]="color.hex"
[attr.aria-label]="color.name"
[attr.aria-selected]="color.hex == selectedColor"
(click)="selectedColor = color.hex; isOpen = false"></div>
</div>
</div>
</ng-template>
(ran into it while working on my angular mix demo)
… on init Currently the focus trap attempts to attach itself once on init (e.g. when it is projected inside of an overlay), however in some cases it might not be in the DOM yet. These changes make it so it re-tries to attach itself until it does so successfully.
2a8943b
to
f01e4bb
Compare
@jelbourn How are we looking on this one? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
@torabian Please do not spam unrelated PRs and issues promoting a project. Further spam will lead to your account being blocked. |
This issue has been automatically locked due to inactivity. Read more about our automatic conversation locking policy. This action has been performed automatically by a bot. |
Currently the focus trap attempts to attach itself once on init (e.g. when it is projected inside of an overlay), however in some cases it might not be in the DOM yet. These changes make it so it re-tries to attach itself until it does so successfully.