Skip to content

Commit

Permalink
fix(cdk/listbox): unable to tab in if active option is removed (#28583)
Browse files Browse the repository at this point in the history
Fixes that the listbox didn't allow focus back in when its active option is removed.

Fixes #28557.

(cherry picked from commit d766b14)
  • Loading branch information
crisbeto committed Feb 13, 2024
1 parent 54ea5ca commit 55eeee3
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 6 deletions.
35 changes: 29 additions & 6 deletions src/cdk/listbox/listbox.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,26 @@ describe('CdkOption and CdkListbox', () => {

expect(optionEls[0].getAttribute('tabindex')).toBe('10');
});

it('should reset the tabindex if the active option is destroyed', () => {
const {fixture, listbox, listboxEl} = setupComponent(ListboxWithOptions);
let options = fixture.nativeElement.querySelectorAll('.cdk-option');
expect(listboxEl.getAttribute('tabindex')).toBe('0');
expect(options[0].getAttribute('tabindex')).toBe('-1');

listbox.focus();
fixture.detectChanges();

expect(listboxEl.getAttribute('tabindex')).toBe('-1');
expect(options[0].getAttribute('tabindex')).toBe('0');

fixture.componentInstance.appleRendered = false;
fixture.detectChanges();
options = fixture.nativeElement.querySelectorAll('.cdk-option');

expect(listboxEl.getAttribute('tabindex')).toBe('0');
expect(options[0].getAttribute('tabindex')).toBe('-1');
});
});

describe('selection', () => {
Expand Down Expand Up @@ -943,12 +963,14 @@ describe('CdkOption and CdkListbox', () => {
[cdkListboxNavigatesDisabledOptions]="!navigationSkipsDisabled"
[cdkListboxValue]="selectedValue"
(cdkListboxValueChange)="onSelectionChange($event)">
<div cdkOption="apple"
[cdkOptionDisabled]="isAppleDisabled"
[id]="appleId"
[tabindex]="appleTabindex">
Apple
</div>
@if (appleRendered) {
<div cdkOption="apple"
[cdkOptionDisabled]="isAppleDisabled"
[id]="appleId"
[tabindex]="appleTabindex">
Apple
</div>
}
<div cdkOption="orange" [cdkOptionDisabled]="isOrangeDisabled">Orange
</div>
<div cdkOption="banana">Banana</div>
Expand All @@ -965,6 +987,7 @@ class ListboxWithOptions {
isActiveDescendant = false;
navigationWraps = true;
navigationSkipsDisabled = true;
appleRendered = true;
listboxId: string;
listboxTabindex: number;
appleId: string;
Expand Down
11 changes: 11 additions & 0 deletions src/cdk/listbox/listbox.ts
Original file line number Diff line number Diff line change
Expand Up @@ -831,6 +831,17 @@ export class CdkListbox<T = unknown> implements AfterContentInit, OnDestroy, Con
}

this.listKeyManager.change.subscribe(() => this._focusActiveOption());

this.options.changes.pipe(takeUntil(this.destroyed)).subscribe(() => {
const activeOption = this.listKeyManager.activeItem;

// If the active option was deleted, we need to reset
// the key manager so it can allow focus back in.
if (activeOption && !this.options.find(option => option === activeOption)) {
this.listKeyManager.setActiveItem(-1);
this.changeDetectorRef.markForCheck();
}
});
}

/** Focus the active option. */
Expand Down

0 comments on commit 55eeee3

Please sign in to comment.