Skip to content

Commit c3e472a

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 8eb59f8 commit c3e472a

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
@@ -14,7 +14,7 @@ $mat-form-field-select-horizontal-end-padding: $mat-form-field-select-arrow-widt
1414
// Remove the native select down arrow and ensure that the native appearance
1515
// does not conflict with the form-field. e.g. Focus indication of the native
1616
// select is undesired since we handle focus as part of the form-field.
17-
select.mat-mdc-input-element {
17+
select.mat-mdc-form-field-control {
1818
-moz-appearance: none;
1919
-webkit-appearance: none;
2020
background-color: transparent;
@@ -80,7 +80,7 @@ $mat-form-field-select-horizontal-end-padding: $mat-form-field-select-arrow-widt
8080

8181
// Add padding on the end of the native select so that the content does not
8282
// overlap with the Material Design arrow.
83-
.mat-mdc-input-element {
83+
.mat-mdc-form-field-control {
8484
padding-right: $mat-form-field-select-horizontal-end-padding;
8585
[dir='rtl'] & {
8686
padding-right: 0;
@@ -91,7 +91,7 @@ $mat-form-field-select-horizontal-end-padding: $mat-form-field-select-arrow-widt
9191
}
9292

9393
@mixin mat-mdc-private-form-field-native-select-color($config) {
94-
select.mat-mdc-input-element {
94+
select.mat-mdc-form-field-control {
9595
// On dark themes we set the native `select` color to some shade of white,
9696
// however the color propagates to all of the `option` elements, which are
9797
// 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
@@ -70,7 +70,7 @@
7070

7171
// MDC uses the `subtitle1` level for the input label and value, but the spec shows `body1` as
7272
// the correct level.
73-
.mat-mdc-input-element,
73+
.mat-mdc-form-field-control,
7474
.mat-mdc-form-field label,
7575
.mat-mdc-form-field-prefix,
7676
.mat-mdc-form-field-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
@@ -889,6 +889,17 @@ describe('MatMdcInput without forms', () => {
889889
expect(formField.classList).toContain('mat-warn');
890890
}));
891891

892+
it('should set a class on the input depending on whether it is in a form field', fakeAsync(() => {
893+
const fixture = createComponent(MatInputInsideOutsideFormField);
894+
fixture.detectChanges();
895+
896+
const inFormField = fixture.nativeElement.querySelector('.inside');
897+
const outsideFormField = fixture.nativeElement.querySelector('.outside');
898+
899+
expect(inFormField.classList).toContain('mat-mdc-form-field-control');
900+
expect(outsideFormField.classList).not.toContain('mat-mdc-form-field-control');
901+
}));
902+
892903
});
893904

894905
describe('MatMdcInput with forms', () => {
@@ -1786,3 +1797,15 @@ class CustomMatInputAccessor {
17861797
class MatInputWithColor {
17871798
color: ThemePalette;
17881799
}
1800+
1801+
1802+
@Component({
1803+
template: `
1804+
<mat-form-field>
1805+
<input class="inside" matNativeControl>
1806+
</mat-form-field>
1807+
1808+
<input class="outside" matNativeControl>
1809+
`
1810+
})
1811+
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)