Skip to content

Commit e9797be

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 ecf4105 commit e9797be

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
@@ -190,11 +190,11 @@ export class MatFormField implements AfterViewInit, OnDestroy, AfterContentCheck
190190
}
191191
private _hintLabel = '';
192192

193-
// Unique id for the hint label.
194-
_hintLabelId = `mat-mdc-hint-${nextUniqueId++}`;
195-
196193
// Unique id for the internal form field label.
197-
_labelId = `mat-mdc-form-field-label-${nextUniqueId++}`;
194+
readonly _labelId = `mat-mdc-form-field-label-${nextUniqueId++}`;
195+
196+
// Unique id for the hint label.
197+
readonly _hintLabelId = `mat-mdc-hint-${nextUniqueId++}`;
198198

199199
/** State of the mat-hint and mat-error animations. */
200200
_subscriptAnimationState = '';
@@ -350,6 +350,13 @@ export class MatFormField implements AfterViewInit, OnDestroy, AfterContentCheck
350350
this._destroyed.complete();
351351
}
352352

353+
/**
354+
* Gets the id of the label element. If no label is present, returns `null`.
355+
*/
356+
getLabelId(): string|null {
357+
return this._hasFloatingLabel() ? this._labelId : null;
358+
}
359+
353360
/**
354361
* Gets an ElementRef for the element that a overlay attached to the form-field
355362
* 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)