Skip to content

Commit c4993ac

Browse files
committed
fix(material/button): avoid setting a tabindex on all link buttons (#22901)
Fixes that the button component was always setting a `tabindex="0"` when it's placed on a link element. This is unnecessary, because links are in the tab order by default. We actually had a test that has an assertion against this, but it was passing by accident because we weren't running change detection before making the asserting. (cherry picked from commit 899d0e1)
1 parent 26c8298 commit c4993ac

File tree

4 files changed

+31
-13
lines changed

4 files changed

+31
-13
lines changed

src/material-experimental/mdc-button/button-base.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ export const MAT_ANCHOR_HOST = {
141141
// Note that we ignore the user-specified tabindex when it's disabled for
142142
// consistency with the `mat-button` applied on native buttons where even
143143
// though they have an index, they're not tabbable.
144-
'[attr.tabindex]': 'disabled ? -1 : (tabIndex || 0)',
144+
'[attr.tabindex]': 'disabled ? -1 : tabIndex',
145145
'[attr.aria-disabled]': 'disabled.toString()',
146146
// MDC automatically applies the primary theme color to the button, but we want to support
147147
// an unthemed version. If color is undefined, apply a CSS class that makes it easy to

src/material-experimental/mdc-button/button.spec.ts

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -170,11 +170,13 @@ describe('MDC-based MatButton', () => {
170170
let fixture = TestBed.createComponent(TestApp);
171171
let testComponent = fixture.debugElement.componentInstance;
172172
let buttonDebugElement = fixture.debugElement.query(By.css('a'))!;
173-
expect(buttonDebugElement.nativeElement.getAttribute('tabIndex')).toBe(null);
173+
fixture.detectChanges();
174+
175+
expect(buttonDebugElement.nativeElement.hasAttribute('tabindex')).toBe(false);
174176

175177
testComponent.isDisabled = true;
176178
fixture.detectChanges();
177-
expect(buttonDebugElement.nativeElement.getAttribute('tabIndex')).toBe('-1');
179+
expect(buttonDebugElement.nativeElement.getAttribute('tabindex')).toBe('-1');
178180
});
179181

180182
it('should add aria-disabled attribute if disabled', () => {
@@ -219,18 +221,26 @@ describe('MDC-based MatButton', () => {
219221
fixture.componentInstance.tabIndex = 3;
220222
fixture.detectChanges();
221223

222-
expect(buttonElement.getAttribute('tabIndex'))
224+
expect(buttonElement.getAttribute('tabindex'))
223225
.withContext('Expected custom tabindex to be set')
224226
.toBe('3');
225227

226228
testComponent.isDisabled = true;
227229
fixture.detectChanges();
228230

229-
expect(buttonElement.getAttribute('tabIndex'))
231+
expect(buttonElement.getAttribute('tabindex'))
230232
.withContext('Expected custom tabindex to be overwritten when disabled.')
231233
.toBe('-1');
232234
});
233235

236+
it('should not set a default tabindex on enabled links', () => {
237+
const fixture = TestBed.createComponent(TestApp);
238+
const buttonElement = fixture.debugElement.query(By.css('a'))!.nativeElement;
239+
fixture.detectChanges();
240+
241+
expect(buttonElement.hasAttribute('tabindex')).toBe(false);
242+
});
243+
234244
describe('change detection behavior', () => {
235245
it('should not run change detection for disabled anchor but should prevent the default behavior and stop event propagation', () => {
236246
const appRef = TestBed.inject(ApplicationRef);

src/material/button/button.spec.ts

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -181,14 +181,14 @@ describe('MatButton', () => {
181181
});
182182

183183
it('should remove tabindex if disabled', () => {
184-
const fixture = TestBed.createComponent(TestApp);
185-
const testComponent = fixture.debugElement.componentInstance;
186-
const buttonDebugElement = fixture.debugElement.query(By.css('a'))!;
187-
expect(buttonDebugElement.nativeElement.getAttribute('tabIndex')).toBe(null);
184+
let fixture = TestBed.createComponent(TestApp);
185+
let testComponent = fixture.debugElement.componentInstance;
186+
let buttonDebugElement = fixture.debugElement.query(By.css('a'))!;
187+
expect(buttonDebugElement.nativeElement.hasAttribute('tabindex')).toBe(false);
188188

189189
testComponent.isDisabled = true;
190190
fixture.detectChanges();
191-
expect(buttonDebugElement.nativeElement.getAttribute('tabIndex')).toBe('-1');
191+
expect(buttonDebugElement.nativeElement.getAttribute('tabindex')).toBe('-1');
192192
});
193193

194194
it('should add aria-disabled attribute if disabled', () => {
@@ -233,18 +233,26 @@ describe('MatButton', () => {
233233
fixture.componentInstance.tabIndex = 3;
234234
fixture.detectChanges();
235235

236-
expect(buttonElement.getAttribute('tabIndex'))
236+
expect(buttonElement.getAttribute('tabindex'))
237237
.withContext('Expected custom tabindex to be set')
238238
.toBe('3');
239239

240240
testComponent.isDisabled = true;
241241
fixture.detectChanges();
242242

243-
expect(buttonElement.getAttribute('tabIndex'))
243+
expect(buttonElement.getAttribute('tabindex'))
244244
.withContext('Expected custom tabindex to be overwritten when disabled.')
245245
.toBe('-1');
246246
});
247247

248+
it('should not set a default tabindex on enabled links', () => {
249+
const fixture = TestBed.createComponent(TestApp);
250+
const buttonElement = fixture.debugElement.query(By.css('a'))!.nativeElement;
251+
fixture.detectChanges();
252+
253+
expect(buttonElement.hasAttribute('tabindex')).toBe(false);
254+
});
255+
248256
describe('change detection behavior', () => {
249257
it('should not run change detection for disabled anchor but should prevent the default behavior and stop event propagation', () => {
250258
const appRef = TestBed.inject(ApplicationRef);

src/material/button/button.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ export class MatButton
162162
// Note that we ignore the user-specified tabindex when it's disabled for
163163
// consistency with the `mat-button` applied on native buttons where even
164164
// though they have an index, they're not tabbable.
165-
'[attr.tabindex]': 'disabled ? -1 : (tabIndex || 0)',
165+
'[attr.tabindex]': 'disabled ? -1 : tabIndex',
166166
'[attr.disabled]': 'disabled || null',
167167
'[attr.aria-disabled]': 'disabled.toString()',
168168
'[class._mat-animation-noopable]': '_animationMode === "NoopAnimations"',

0 commit comments

Comments
 (0)