Skip to content

Commit 8e9dade

Browse files
devversionjelbourn
authored andcommitted
feat(slider): support specifying tabindex (#7848)
* Provides a consistent API for developers to specify the tabIndex for the slider * Disabled sliders are no longer tabbable (for accessibility reasons)
1 parent ad7cb4a commit 8e9dade

File tree

2 files changed

+61
-5
lines changed

2 files changed

+61
-5
lines changed

src/lib/slider/slider.spec.ts

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ describe('MatSlider without forms', () => {
3939
SliderWithValueGreaterThanMax,
4040
SliderWithChangeHandler,
4141
SliderWithDirAndInvert,
42+
SliderWithTabIndexBinding,
43+
SliderWithNativeTabindexAttr,
4244
VerticalSlider,
4345
],
4446
providers: [
@@ -268,6 +270,10 @@ describe('MatSlider without forms', () => {
268270
it ('should leave thumb gap', () => {
269271
expect(trackFillElement.style.transform).toContain('translateX(-7px)');
270272
});
273+
274+
it('should disable tabbing to the slider', () => {
275+
expect(sliderNativeElement.tabIndex).toBe(-1);
276+
});
271277
});
272278

273279
describe('slider with set min and max', () => {
@@ -1163,6 +1169,33 @@ describe('MatSlider without forms', () => {
11631169
expect(sliderNativeElement.getAttribute('aria-orientation')).toEqual('vertical');
11641170
});
11651171
});
1172+
1173+
describe('tabindex', () => {
1174+
1175+
it('should allow setting the tabIndex through binding', () => {
1176+
const fixture = TestBed.createComponent(SliderWithTabIndexBinding);
1177+
fixture.detectChanges();
1178+
1179+
const slider = fixture.debugElement.query(By.directive(MatSlider)).componentInstance;
1180+
1181+
expect(slider.tabIndex).toBe(0, 'Expected the tabIndex to be set to 0 by default.');
1182+
1183+
fixture.componentInstance.tabIndex = 3;
1184+
fixture.detectChanges();
1185+
1186+
expect(slider.tabIndex).toBe(3, 'Expected the tabIndex to have been changed.');
1187+
});
1188+
1189+
it('should detect the native tabindex attribute', () => {
1190+
const fixture = TestBed.createComponent(SliderWithNativeTabindexAttr);
1191+
fixture.detectChanges();
1192+
1193+
const slider = fixture.debugElement.query(By.directive(MatSlider)).componentInstance;
1194+
1195+
expect(slider.tabIndex)
1196+
.toBe(5, 'Expected the tabIndex to be set to the value of the native attribute.');
1197+
});
1198+
});
11661199
});
11671200

11681201
describe('MatSlider with forms module', () => {
@@ -1465,6 +1498,22 @@ class VerticalSlider {
14651498
invert = false;
14661499
}
14671500

1501+
@Component({
1502+
template: `<mat-slider [tabIndex]="tabIndex"></mat-slider>`,
1503+
styles: [styles],
1504+
})
1505+
class SliderWithTabIndexBinding {
1506+
tabIndex: number;
1507+
}
1508+
1509+
@Component({
1510+
template: `<mat-slider tabindex="5"></mat-slider>`,
1511+
styles: [styles],
1512+
})
1513+
class SliderWithNativeTabindexAttr {
1514+
tabIndex: number;
1515+
}
1516+
14681517
/**
14691518
* Dispatches a click event sequence (consisting of moueseenter, click) from an element.
14701519
* Note: The mouse event truncates the position for the click.

src/lib/slider/slider.ts

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import {
2020
UP_ARROW,
2121
} from '@angular/cdk/keycodes';
2222
import {
23+
Attribute,
2324
ChangeDetectionStrategy,
2425
ChangeDetectorRef,
2526
Component,
@@ -40,8 +41,10 @@ import {
4041
CanColor,
4142
CanDisable,
4243
HammerInput,
44+
HasTabIndex,
4345
mixinColor,
4446
mixinDisabled,
47+
mixinTabIndex,
4548
} from '@angular/material/core';
4649
import {Subscription} from 'rxjs/Subscription';
4750

@@ -85,7 +88,8 @@ export class MatSliderChange {
8588
export class MatSliderBase {
8689
constructor(public _renderer: Renderer2, public _elementRef: ElementRef) {}
8790
}
88-
export const _MatSliderMixinBase = mixinColor(mixinDisabled(MatSliderBase), 'accent');
91+
export const _MatSliderMixinBase =
92+
mixinTabIndex(mixinColor(mixinDisabled(MatSliderBase), 'accent'));
8993

9094
/**
9195
* Allows users to select from a range of values by moving the slider thumb. It is similar in
@@ -108,7 +112,7 @@ export const _MatSliderMixinBase = mixinColor(mixinDisabled(MatSliderBase), 'acc
108112
'(slidestart)': '_onSlideStart($event)',
109113
'class': 'mat-slider',
110114
'role': 'slider',
111-
'tabindex': '0',
115+
'[tabIndex]': 'tabIndex',
112116
'[attr.aria-disabled]': 'disabled',
113117
'[attr.aria-valuemax]': 'max',
114118
'[attr.aria-valuemin]': 'min',
@@ -126,13 +130,13 @@ export const _MatSliderMixinBase = mixinColor(mixinDisabled(MatSliderBase), 'acc
126130
},
127131
templateUrl: 'slider.html',
128132
styleUrls: ['slider.css'],
129-
inputs: ['disabled', 'color'],
133+
inputs: ['disabled', 'color', 'tabIndex'],
130134
encapsulation: ViewEncapsulation.None,
131135
preserveWhitespaces: false,
132136
changeDetection: ChangeDetectionStrategy.OnPush,
133137
})
134138
export class MatSlider extends _MatSliderMixinBase
135-
implements ControlValueAccessor, OnDestroy, CanDisable, CanColor, OnInit {
139+
implements ControlValueAccessor, OnDestroy, CanDisable, CanColor, OnInit, HasTabIndex {
136140
/** Whether the slider is inverted. */
137141
@Input()
138142
get invert() { return this._invert; }
@@ -418,8 +422,11 @@ export class MatSlider extends _MatSliderMixinBase
418422
elementRef: ElementRef,
419423
private _focusMonitor: FocusMonitor,
420424
private _changeDetectorRef: ChangeDetectorRef,
421-
@Optional() private _dir: Directionality) {
425+
@Optional() private _dir: Directionality,
426+
@Attribute('tabindex') tabIndex: string) {
422427
super(renderer, elementRef);
428+
429+
this.tabIndex = parseInt(tabIndex) || 0;
423430
}
424431

425432
ngOnInit() {

0 commit comments

Comments
 (0)