diff --git a/src/lib/select/select.spec.ts b/src/lib/select/select.spec.ts
index df1fb46f739a..06b76d43c858 100644
--- a/src/lib/select/select.spec.ts
+++ b/src/lib/select/select.spec.ts
@@ -1085,6 +1085,21 @@ describe('MdSelect', () => {
expect(select.getAttribute('aria-label')).toEqual('Food');
});
+ it('should support setting a custom aria-label', () => {
+ fixture.componentInstance.ariaLabel = 'Custom Label';
+ fixture.detectChanges();
+
+ expect(select.getAttribute('aria-label')).toEqual('Custom Label');
+ });
+
+ it('should not set an aria-label if aria-labelledby is specified', () => {
+ fixture.componentInstance.ariaLabelledby = 'myLabelId';
+ fixture.detectChanges();
+
+ expect(select.getAttribute('aria-label')).toBeFalsy('Expected no aria-label to be set.');
+ expect(select.getAttribute('aria-labelledby')).toBe('myLabelId');
+ });
+
it('should set the tabindex of the select to 0 by default', () => {
expect(select.getAttribute('tabindex')).toEqual('0');
});
@@ -1606,7 +1621,7 @@ describe('MdSelect', () => {
template: `
+ [tabIndex]="tabIndexOverride" [aria-label]="ariaLabel" [aria-labelledby]="ariaLabelledby">
{{ food.viewValue }}
@@ -1630,6 +1645,8 @@ class BasicSelect {
heightAbove = 0;
heightBelow = 0;
tabIndexOverride: number;
+ ariaLabel: string;
+ ariaLabelledby: string;
@ViewChild(MdSelect) select: MdSelect;
@ViewChildren(MdOption) options: QueryList;
diff --git a/src/lib/select/select.ts b/src/lib/select/select.ts
index c220082e5db2..4a1afaa0c409 100644
--- a/src/lib/select/select.ts
+++ b/src/lib/select/select.ts
@@ -101,7 +101,8 @@ export type MdSelectFloatPlaceholderType = 'always' | 'never' | 'auto';
host: {
'role': 'listbox',
'[attr.tabindex]': 'tabIndex',
- '[attr.aria-label]': 'placeholder',
+ '[attr.aria-label]': '_ariaLabel',
+ '[attr.aria-labelledby]': 'ariaLabelledby',
'[attr.aria-required]': 'required.toString()',
'[attr.aria-disabled]': 'disabled.toString()',
'[attr.aria-invalid]': '_control?.invalid || "false"',
@@ -279,6 +280,12 @@ export class MdSelect implements AfterContentInit, ControlValueAccessor, OnDestr
}
}
+ /** Aria label of the select. If not specified, the placeholder will be used as label. */
+ @Input('aria-label') ariaLabel: string = '';
+
+ /** Input that can be used to specify the `aria-labelledby` attribute. */
+ @Input('aria-labelledby') ariaLabelledby: string = '';
+
/** Combined stream of all of the child options' change events. */
get optionSelectionChanges(): Observable {
return Observable.merge(...this.options.map(option => option.onSelectionChange));
@@ -747,6 +754,13 @@ export class MdSelect implements AfterContentInit, ControlValueAccessor, OnDestr
'visible' : 'hidden';
}
+ /** Returns the aria-label of the select component. */
+ get _ariaLabel(): string {
+ // If an ariaLabelledby value has been set, the select should not overwrite the
+ // `aria-labelledby` value by setting the ariaLabel to the placeholder.
+ return this.ariaLabelledby ? null : this.ariaLabel || this.placeholder;
+ }
+
/**
* Calculates the y-offset of the select's overlay panel in relation to the
* top start corner of the trigger. It has to be adjusted in order for the