Skip to content

Commit 617ca87

Browse files
committed
feat(form-field): expose label element id for custom controls
Currently, the form-field always creates a label element as sibling to projected form-field controls. For native controls, the label is associated with the controls using the `for` attribute. This doesn't work for custom controls which might not be based on native controls. e.g. the `mat-select`. In those cases, the appropriate aria attributes need to be applied with `aria-labelledby` that refers to the label content element. Since this is a common pattern for custom controls that don't use native controls, we need to expose the element id for the label content. Currently we already do this for the select, but just prefixed it with an underscore. This denotes it as private API while there is obviously a use-case for exposing this publicly. Best example is how the select _needs_ it.
1 parent 298cdc0 commit 617ca87

File tree

4 files changed

+25
-10
lines changed

4 files changed

+25
-10
lines changed

src/material-experimental/mdc-form-field/form-field.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -192,11 +192,11 @@ export class MatFormField implements AfterViewInit, OnDestroy, AfterContentCheck
192192
}
193193
private _hintLabel = '';
194194

195-
// Unique id for the hint label.
196-
_hintLabelId = `mat-mdc-hint-${nextUniqueId++}`;
197-
198195
// Unique id for the internal form field label.
199-
_labelId = `mat-mdc-form-field-label-${nextUniqueId++}`;
196+
readonly _labelId = `mat-mdc-form-field-label-${nextUniqueId++}`;
197+
198+
// Unique id for the hint label.
199+
readonly _hintLabelId = `mat-mdc-hint-${nextUniqueId++}`;
200200

201201
/** State of the mat-hint and mat-error animations. */
202202
_subscriptAnimationState = '';
@@ -358,6 +358,13 @@ export class MatFormField implements AfterViewInit, OnDestroy, AfterContentCheck
358358
this._destroyed.complete();
359359
}
360360

361+
/**
362+
* Gets the id of the label element. If no label is present, returns `null`.
363+
*/
364+
getLabelId(): string|null {
365+
return this._hasFloatingLabel() ? this._labelId : null;
366+
}
367+
361368
/**
362369
* Gets an ElementRef for the element that a overlay attached to the form-field
363370
* should be positioned relative to.

src/material/form-field/form-field.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -219,10 +219,10 @@ export class MatFormField extends _MatFormFieldMixinBase
219219
private _hintLabel = '';
220220

221221
// Unique id for the hint label.
222-
_hintLabelId: string = `mat-hint-${nextUniqueId++}`;
222+
readonly _hintLabelId: string = `mat-hint-${nextUniqueId++}`;
223223

224-
// Unique id for the internal form field label.
225-
_labelId = `mat-form-field-label-${nextUniqueId++}`;
224+
// Unique id for the label element.
225+
readonly _labelId = `mat-form-field-label-${nextUniqueId++}`;
226226

227227
/**
228228
* Whether the label should always float, never float or float as the user types.
@@ -300,6 +300,13 @@ export class MatFormField extends _MatFormFieldMixinBase
300300
_defaults.hideRequiredMarker : false;
301301
}
302302

303+
/**
304+
* Gets the id of the label element. If no label is present, returns `null`.
305+
*/
306+
getLabelId(): string|null {
307+
return this._hasFloatingLabel() ? this._labelId : null;
308+
}
309+
303310
/**
304311
* Gets an ElementRef for the element that a overlay attached to the form-field should be
305312
* positioned relative to.

src/material/select/select.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1168,7 +1168,7 @@ export class MatSelect extends _MatSelectMixinBase implements AfterContentInit,
11681168
return null;
11691169
}
11701170

1171-
return this._parentFormField._labelId || null;
1171+
return this._parentFormField.getLabelId();
11721172
}
11731173

11741174
/** Determines the `aria-activedescendant` to be set on the host. */

tools/public_api_guard/material/form-field.d.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,12 @@ export declare class MatFormField extends _MatFormFieldMixinBase implements Afte
2828
_elementRef: ElementRef;
2929
_errorChildren: QueryList<MatError>;
3030
_hintChildren: QueryList<MatHint>;
31-
_hintLabelId: string;
31+
readonly _hintLabelId: string;
3232
_inputContainerRef: ElementRef;
3333
get _labelChild(): MatLabel;
3434
_labelChildNonStatic: MatLabel;
3535
_labelChildStatic: MatLabel;
36-
_labelId: string;
36+
readonly _labelId: string;
3737
_placeholderChild: MatPlaceholder;
3838
_prefixChildren: QueryList<MatPrefix>;
3939
get _shouldAlwaysFloat(): boolean;
@@ -59,6 +59,7 @@ export declare class MatFormField extends _MatFormFieldMixinBase implements Afte
5959
_shouldLabelFloat(): boolean;
6060
protected _validateControlChild(): void;
6161
getConnectedOverlayOrigin(): ElementRef;
62+
getLabelId(): string | null;
6263
ngAfterContentChecked(): void;
6364
ngAfterContentInit(): void;
6465
ngAfterViewInit(): void;

0 commit comments

Comments
 (0)