Skip to content

Commit ad63734

Browse files
committed
fix(material/core): remove tabindex from mat-option
Remove the tabindex attribute from MatOption. MatOption will no longer set a tabindex. Tabindex is not needed since focus is managed on the parent by setting `aria-activedescendant`. Tabindex="-1" seems to be causing a problem in #26861 where VoiceOver with Firefox moves DOM focus from the combobox to the option when opening the listbox popup.
1 parent cb29697 commit ad63734

File tree

3 files changed

+22
-11
lines changed

3 files changed

+22
-11
lines changed

src/material/core/option/option.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ export class _MatOptionBase<T = any> implements FocusableOption, AfterViewChecke
205205
}
206206

207207
/** Returns the correct tabindex for the option depending on disabled state. */
208-
_getTabIndex(): string {
208+
_getTabIndex(): string | null {
209209
return this.disabled ? '-1' : '0';
210210
}
211211

@@ -286,6 +286,10 @@ export class MatOption<T = any> extends _MatOptionBase<T> {
286286
) {
287287
super(element, changeDetectorRef, parent, group);
288288
}
289+
290+
override _getTabIndex(): string | null {
291+
return null;
292+
}
289293
}
290294

291295
/**

src/material/select/select.spec.ts

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -824,17 +824,25 @@ describe('MDC-based MatSelect', () => {
824824
'mat-option',
825825
) as NodeListOf<HTMLElement>;
826826

827-
options[3].focus();
827+
select.focus();
828+
multiFixture.detectChanges();
829+
828830
expect(document.activeElement)
829-
.withContext('Expected fourth option to be focused.')
830-
.toBe(options[3]);
831+
.withContext('Expected select to have DOM focus')
832+
.toBe(select);
833+
expect(select.getAttribute('aria-activedescendant'))
834+
.withContext('Expected the first option to be activated.')
835+
.toBe(options[0].id);
831836

832837
multiFixture.componentInstance.control.setValue(['steak-0', 'sushi-7']);
833838
multiFixture.detectChanges();
834839

835840
expect(document.activeElement)
836-
.withContext('Expected fourth option to remain focused.')
837-
.toBe(options[3]);
841+
.withContext('Expected select to have DOM focus')
842+
.toBe(select);
843+
expect(select.getAttribute('aria-activedescendant'))
844+
.withContext('Expected first option to remain activated.')
845+
.toBe(options[0].id);
838846
}),
839847
);
840848

@@ -1260,10 +1268,10 @@ describe('MDC-based MatSelect', () => {
12601268
.toBe(true);
12611269
}));
12621270

1263-
it('should set the tabindex of each option according to disabled state', fakeAsync(() => {
1264-
expect(options[0].getAttribute('tabindex')).toEqual('0');
1265-
expect(options[1].getAttribute('tabindex')).toEqual('0');
1266-
expect(options[2].getAttribute('tabindex')).toEqual('-1');
1271+
it('should omit the tabindex attribute on each option', fakeAsync(() => {
1272+
expect(options[0].hasAttribute('tabindex')).toBeFalse();
1273+
expect(options[1].hasAttribute('tabindex')).toBeFalse();
1274+
expect(options[2].hasAttribute('tabindex')).toBeFalse();
12671275
}));
12681276

12691277
it('should set aria-disabled for disabled options', fakeAsync(() => {

tools/public_api_guard/material/core.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,6 @@ export class _MatOptionBase<T = any> implements FocusableOption, AfterViewChecke
281281
focus(_origin?: FocusOrigin, options?: FocusOptions): void;
282282
_getHostElement(): HTMLElement;
283283
getLabel(): string;
284-
_getTabIndex(): string;
285284
// (undocumented)
286285
readonly group: _MatOptgroupBase;
287286
_handleKeydown(event: KeyboardEvent): void;

0 commit comments

Comments
 (0)