Skip to content

Commit 7c2c448

Browse files
committed
fix(material-experimental/mdc-input): only apply styling when inside a form field
Currently `mat-form-field` brings in the styles for `MatInput`. but the problem is that they target a class that is applied even to inputs that aren't inside a form field. These changes aim to prevent CSS from bleeding out by only styling inputs inside a `mat-form-field`. Fixes #21871.
1 parent db6511b commit 7c2c448

File tree

9 files changed

+62
-14
lines changed

9 files changed

+62
-14
lines changed

src/material-experimental/mdc-chips/chip-input.spec.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ describe('MDC-based MatChipInput', () => {
130130

131131
it('should set input styling classes', () => {
132132
expect(inputNativeElement.classList).toContain('mat-mdc-input-element');
133+
expect(inputNativeElement.classList).toContain('mat-mdc-form-field-control');
133134
expect(inputNativeElement.classList).toContain('mat-mdc-chip-input');
134135
expect(inputNativeElement.classList).toContain('mdc-text-field__input');
135136
});

src/material-experimental/mdc-chips/chip-input.ts

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,17 @@
88

99
import {BooleanInput, coerceBooleanProperty} from '@angular/cdk/coercion';
1010
import {hasModifierKey, TAB} from '@angular/cdk/keycodes';
11-
import {Directive, ElementRef, EventEmitter, Inject, Input, OnChanges, Output} from '@angular/core';
11+
import {
12+
Directive,
13+
ElementRef,
14+
EventEmitter,
15+
Inject,
16+
Input,
17+
OnChanges,
18+
Optional,
19+
Output,
20+
} from '@angular/core';
21+
import {MatFormField, MAT_FORM_FIELD} from '@angular/material-experimental/mdc-form-field';
1222
import {MatChipsDefaultOptions, MAT_CHIPS_DEFAULT_OPTIONS} from './chip-default-options';
1323
import {MatChipGrid} from './chip-grid';
1424
import {MatChipTextControl} from './chip-text-control';
@@ -104,9 +114,14 @@ export class MatChipInput implements MatChipTextControl, OnChanges {
104114

105115
constructor(
106116
protected _elementRef: ElementRef<HTMLInputElement>,
107-
@Inject(MAT_CHIPS_DEFAULT_OPTIONS) private _defaultOptions: MatChipsDefaultOptions) {
108-
this._inputElement = this._elementRef.nativeElement as HTMLInputElement;
109-
}
117+
@Inject(MAT_CHIPS_DEFAULT_OPTIONS) private _defaultOptions: MatChipsDefaultOptions,
118+
@Optional() @Inject(MAT_FORM_FIELD) formField?: MatFormField) {
119+
this._inputElement = this._elementRef.nativeElement as HTMLInputElement;
120+
121+
if (formField) {
122+
this._inputElement.classList.add('mat-mdc-form-field-control');
123+
}
124+
}
110125

111126
ngOnChanges() {
112127
this._chipGrid.stateChanges.next();

src/material-experimental/mdc-form-field/_form-field-native-select.scss

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ $mat-form-field-select-horizontal-end-padding: $mat-form-field-select-arrow-widt
1616
// Remove the native select down arrow and ensure that the native appearance
1717
// does not conflict with the form-field. e.g. Focus indication of the native
1818
// select is undesired since we handle focus as part of the form-field.
19-
select.mat-mdc-input-element {
19+
select.mat-mdc-form-field-control {
2020
-moz-appearance: none;
2121
-webkit-appearance: none;
2222
background-color: transparent;
@@ -82,7 +82,7 @@ $mat-form-field-select-horizontal-end-padding: $mat-form-field-select-arrow-widt
8282

8383
// Add padding on the end of the native select so that the content does not
8484
// overlap with the Material Design arrow.
85-
.mat-mdc-input-element {
85+
.mat-mdc-form-field-control {
8686
padding-right: $mat-form-field-select-horizontal-end-padding;
8787
[dir='rtl'] & {
8888
padding-right: 0;
@@ -93,7 +93,7 @@ $mat-form-field-select-horizontal-end-padding: $mat-form-field-select-arrow-widt
9393
}
9494

9595
@mixin private-form-field-native-select-color($config) {
96-
select.mat-mdc-input-element {
96+
select.mat-mdc-form-field-control {
9797
// On dark themes we set the native `select` color to some shade of white,
9898
// however the color propagates to all of the `option` elements, which are
9999
// always on a white background inside the dropdown, causing them to blend in.

src/material-experimental/mdc-form-field/_form-field-theme.scss

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@
7373

7474
// MDC uses the `subtitle1` level for the input label and value, but the spec shows `body1` as
7575
// the correct level.
76-
.mat-mdc-input-element,
76+
.mat-mdc-form-field-control,
7777
.mat-mdc-form-field label,
7878
.mat-mdc-form-field-text-prefix,
7979
.mat-mdc-form-field-text-suffix {

src/material-experimental/mdc-form-field/_mdc-text-field-structure-overrides.scss

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
// Unset the border set by MDC. We move the border (which serves as the Material Design
1111
// text-field bottom line) into its own element. This is necessary because we want the
1212
// bottom-line to span across the whole form-field (including prefixes and suffixes).
13-
.mat-mdc-input-element {
13+
.mat-mdc-form-field-control {
1414
border: none;
1515
}
1616

@@ -27,8 +27,8 @@
2727
// not work for us since we support arbitrary form field controls which don't necessarily
2828
// use an `input` element. We organize the vertical spacing on the infix container.
2929
.mdc-text-field--no-label:not(.mdc-text-field--textarea)
30-
.mat-mdc-input-element.mdc-text-field__input,
31-
.mat-mdc-text-field-wrapper .mat-mdc-input-element {
30+
.mat-mdc-form-field-control.mdc-text-field__input,
31+
.mat-mdc-text-field-wrapper .mat-mdc-form-field-control {
3232
height: auto;
3333
}
3434

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

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -896,6 +896,17 @@ describe('MatMdcInput without forms', () => {
896896
expect(formField.classList).toContain('mat-warn');
897897
}));
898898

899+
it('should set a class on the input depending on whether it is in a form field', fakeAsync(() => {
900+
const fixture = createComponent(MatInputInsideOutsideFormField);
901+
fixture.detectChanges();
902+
903+
const inFormField = fixture.nativeElement.querySelector('.inside');
904+
const outsideFormField = fixture.nativeElement.querySelector('.outside');
905+
906+
expect(inFormField.classList).toContain('mat-mdc-form-field-control');
907+
expect(outsideFormField.classList).not.toContain('mat-mdc-form-field-control');
908+
}));
909+
899910
});
900911

901912
describe('MatMdcInput with forms', () => {
@@ -1796,3 +1807,15 @@ class CustomMatInputAccessor {
17961807
class MatInputWithColor {
17971808
color: ThemePalette;
17981809
}
1810+
1811+
1812+
@Component({
1813+
template: `
1814+
<mat-form-field>
1815+
<input class="inside" matNativeControl>
1816+
</mat-form-field>
1817+
1818+
<input class="outside" matNativeControl>
1819+
`
1820+
})
1821+
class MatInputInsideOutsideFormField {}

src/material-experimental/mdc-input/input.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,17 @@ import {MatInput as BaseMatInput} from '@angular/material/input';
1919
input[matNativeControl], textarea[matNativeControl]`,
2020
exportAs: 'matInput',
2121
host: {
22-
'class': 'mat-mdc-input-element mdc-text-field__input',
23-
// The BaseMatInput parent class adds `mat-input-element` and `mat-form-field-autofill-control`
24-
// to the CSS classlist, but this should not be added for this MDC equivalent input.
22+
'class': 'mat-mdc-input-element',
23+
// The BaseMatInput parent class adds `mat-input-element`, `mat-form-field-control` and
24+
// `mat-form-field-autofill-control` to the CSS class list, but this should not be added for
25+
// this MDC equivalent input.
2526
'[class.mat-form-field-autofill-control]': 'false',
2627
'[class.mat-input-element]': 'false',
28+
'[class.mat-form-field-control]': 'false',
2729
'[class.mat-input-server]': '_isServer',
2830
'[class.mat-mdc-textarea-input]': '_isTextarea',
31+
'[class.mat-mdc-form-field-control]': '_isInFormField',
32+
'[class.mdc-text-field__input]': '_isInFormField',
2933
// Native input properties that are overwritten by Angular inputs need to be synced with
3034
// the native input element. Otherwise property bindings for those don't work.
3135
'[id]': 'id',

src/material/input/input.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,9 @@ export class MatInput extends _MatInputMixinBase implements MatFormFieldControl<
107107
/** Whether the component is a textarea. */
108108
readonly _isTextarea: boolean;
109109

110+
/** Whether the input is inside of a form field. */
111+
readonly _isInFormField: boolean;
112+
110113
/**
111114
* Implemented as part of MatFormFieldControl.
112115
* @docs-private
@@ -282,6 +285,7 @@ export class MatInput extends _MatInputMixinBase implements MatFormFieldControl<
282285
this._isServer = !this._platform.isBrowser;
283286
this._isNativeSelect = nodeName === 'select';
284287
this._isTextarea = nodeName === 'textarea';
288+
this._isInFormField = !!_formField;
285289

286290
if (this._isNativeSelect) {
287291
this.controlType = (element as HTMLSelectElement).multiple ? 'mat-native-select-multiple' :

tools/public_api_guard/material/input.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ export declare class MatInput extends _MatInputMixinBase implements MatFormField
88
protected _disabled: boolean;
99
protected _elementRef: ElementRef<HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement>;
1010
protected _id: string;
11+
readonly _isInFormField: boolean;
1112
readonly _isNativeSelect: boolean;
1213
readonly _isServer: boolean;
1314
readonly _isTextarea: boolean;

0 commit comments

Comments
 (0)