Skip to content

Commit 75b57d4

Browse files
author
Vivian Hu
committed
feat(input): add native select to be form input
1 parent 0f74838 commit 75b57d4

File tree

15 files changed

+65
-60
lines changed

15 files changed

+65
-60
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ npm-debug.log
3939
testem.log
4040
/.chrome
4141
/.git
42+
/.firebase
4243

4344
# schematics
4445
/src/lib/schematics/**/*.js

src/demo-app/input/input-demo.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
<form>
55
<mat-form-field class="demo-full-width">
66
<mat-label>Company (disabled)</mat-label>
7-
<input matInput disabled value="Google">
7+
<input matNativeControl disabled value="Google">
88
</mat-form-field>
99

1010
<table style="width: 100%" cellspacing="0"><tr>
@@ -28,7 +28,7 @@
2828
</mat-form-field>
2929
<mat-form-field class="demo-full-width">
3030
<mat-label>Address 2</mat-label>
31-
<textarea matInput></textarea>
31+
<textarea matNativeControl></textarea>
3232
</mat-form-field>
3333
</p>
3434
<table style="width: 100%" cellspacing="0"><tr>

src/demo-app/select/select-demo.html

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
<h4>Basic</h4>
88
<mat-form-field class="demo-full-width">
99
<mat-label>Select your car</mat-label>
10-
<select matControl id="mySelectId">
10+
<select matNativeControl id="mySelectId">
1111
<option value="" disabled selected></option>
1212
<option value="volvo">Volvo</option>
1313
<option value="saab" disabled>Saab</option>
@@ -18,7 +18,7 @@ <h4>Basic</h4>
1818
<h4>Disabled and required</h4>
1919
<mat-form-field class="demo-full-width">
2020
<mat-label>Select your car (disabled)</mat-label>
21-
<select matControl disabled required>
21+
<select matNativeControl disabled required>
2222
<option value="volvo">Volvo</option>
2323
<option value="saab">Saab</option>
2424
<option value="mercedes">Mercedes</option>
@@ -28,7 +28,7 @@ <h4>Disabled and required</h4>
2828
<h4>Floating label</h4>
2929
<mat-form-field>
3030
<mat-label>Float with value</mat-label>
31-
<select matControl>
31+
<select matNativeControl>
3232
<option value="volvo">Volvo</option>
3333
<option value="saab">Saab</option>
3434
<option value="mercedes">Mercedes</option>
@@ -37,7 +37,7 @@ <h4>Floating label</h4>
3737
</mat-form-field>
3838
<mat-form-field>
3939
<mat-label>Not float when empty</mat-label>
40-
<select matControl>
40+
<select matNativeControl>
4141
<option value="" selected></option>
4242
<option value="saab">Saab</option>
4343
<option value="mercedes">Mercedes</option>
@@ -46,7 +46,7 @@ <h4>Floating label</h4>
4646
</mat-form-field>
4747
<mat-form-field>
4848
<mat-label>Float with no value, but with label</mat-label>
49-
<select matControl>
49+
<select matNativeControl>
5050
<option value="" selected label="--select one--"></option>
5151
<option value="saab">Saab</option>
5252
<option value="mercedes">Mercedes</option>
@@ -55,7 +55,7 @@ <h4>Floating label</h4>
5555
</mat-form-field>
5656
<mat-form-field>
5757
<mat-label>Float with no value, but with html</mat-label>
58-
<select matControl>
58+
<select matNativeControl>
5959
<option value="" selected>--select one--</option>
6060
<option value="saab">Saab</option>
6161
<option value="mercedes">Mercedes</option>
@@ -65,7 +65,7 @@ <h4>Floating label</h4>
6565
<h4>Looks</h4>
6666
<mat-form-field appearance="legacy">
6767
<mat-label>Legacy</mat-label>
68-
<select matControl required>
68+
<select matNativeControl required>
6969
<option value="volvo">Volvo</option>
7070
<option value="saab">Saab</option>
7171
<option value="mercedes">Mercedes</option>
@@ -74,7 +74,7 @@ <h4>Looks</h4>
7474
</mat-form-field>
7575
<mat-form-field appearance="standard">
7676
<mat-label>Standard</mat-label>
77-
<select matControl required>
77+
<select matNativeControl required>
7878
<option value="volvo">Volvo</option>
7979
<option value="saab">Saab</option>
8080
<option value="mercedes">Mercedes</option>
@@ -83,7 +83,7 @@ <h4>Looks</h4>
8383
</mat-form-field>
8484
<mat-form-field appearance="fill">
8585
<mat-label>Fill</mat-label>
86-
<select matControl required>
86+
<select matNativeControl required>
8787
<option value="volvo">Volvo</option>
8888
<option value="saab">Saab</option>
8989
<option value="mercedes">Mercedes</option>
@@ -92,7 +92,7 @@ <h4>Looks</h4>
9292
</mat-form-field>
9393
<mat-form-field appearance="outline">
9494
<mat-label>Outline</mat-label>
95-
<select matControl>
95+
<select matNativeControl>
9696
<option value="volvo">volvo</option>
9797
<option value="saab">Saab</option>
9898
<option value="mercedes">Mercedes</option>
@@ -101,7 +101,7 @@ <h4>Looks</h4>
101101
</mat-form-field>
102102
<h4>Option group</h4>
103103
<mat-form-field>
104-
<select matControl>
104+
<select matNativeControl>
105105
<optgroup label="Swedish Cars">
106106
<option value="volvo">volvo</option>
107107
<option value="saab">Saab</option>
@@ -114,7 +114,7 @@ <h4>Option group</h4>
114114
</mat-form-field>
115115
<h4>Place holder</h4>
116116
<mat-form-field class="demo-full-width">
117-
<select matControl placeholder="place holder">
117+
<select matNativeControl placeholder="place holder">
118118
<option value="" disabled selected></option>
119119
<option value="volvo">Volvo</option>
120120
<option value="saab" disabled>Saab</option>
@@ -125,7 +125,7 @@ <h4>Place holder</h4>
125125
<h4>Error message, hint, form sumbit</h4>
126126
<mat-form-field class="demo-full-width">
127127
<mat-label>Select your car (required)</mat-label>
128-
<select matControl required [formControl]="selectFormControl">
128+
<select matNativeControl required [formControl]="selectFormControl">
129129
<option label="--select something --"></option>
130130
<option value="saab">Saab</option>
131131
<option value="mercedes">Mercedes</option>
@@ -140,7 +140,7 @@ <h4>Error message, hint, form sumbit</h4>
140140
<h4>Error message with errorStateMatcher</h4>
141141
<mat-form-field class="demo-full-width">
142142
<mat-label>Select your car</mat-label>
143-
<select matControl required [formControl]="selectFormControl" [errorStateMatcher]="matcher">
143+
<select matNativeControl required [formControl]="selectFormControl" [errorStateMatcher]="matcher">
144144
<option label="--select something --"></option>
145145
<option value="saab">Saab</option>
146146
<option value="mercedes">Mercedes</option>

src/lib/form-field/form-field.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ In this document, "form field" refers to the wrapper component `<mat-form-field>
77
(e.g. the input, textarea, select, etc.)
88

99
The following Angular Material components are designed to work inside a `<mat-form-field>`:
10-
* [`<input matInput>` &amp; `<textarea matInput>`](https://material.angular.io/components/input/overview)
11-
* [`<select matInput>`](https://material.angular.io/components/select/overview)
10+
* [`<input matNativeControl>` &amp; `<textarea matNativeControl>`](https://material.angular.io/components/input/overview)
11+
* [`<select matNativeControl>`](https://material.angular.io/components/select/overview)
1212
* [`<mat-select>`](https://material.angular.io/components/select/overview)
1313
* [`<mat-chip-list>`](https://material.angular.io/components/chips/overview)
1414

@@ -42,7 +42,7 @@ want a floating label, add a `<mat-label>` to the `mat-form-field`.
4242
### Floating label
4343

4444
The floating label is a text label displayed on top of the form field control when
45-
the control does not contain any text or when `<select matInput>` does not show any option text.
45+
the control does not contain any text or when `<select matNativeControl>` does not show any option text.
4646
By default, when text is present the floating label
4747
floats above the form field control. The label for a form field can be specified by adding a
4848
`mat-label` element.

src/lib/input/input.scss

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -122,17 +122,16 @@ textarea.mat-input-element {
122122
margin: -2px 0;
123123
}
124124

125-
// Remove select button from IE11
126-
select.mat-input-element::-ms-expand {
127-
display: none;
128-
}
129-
130-
//encoded material design select arrow svg
125+
// Encoded material design select arrow svg
131126
/* stylelint-disable max-line-length */
132127
$mat-native-select-arrow-svg: 'data:image/svg+xml;charset=utf8,%3Csvg%20width%3D%2210%22%20height%3D%225%22%20viewBox%3D%227%2010%2010%205%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20fill%3D%22%230%22%20fill-rule%3D%22evenodd%22%20opacity%3D%22.54%22%20d%3D%22M7%2010l5%205%205-5z%22%2F%3E%3C%2Fsvg%3E';
133128
/* stylelint-enable */
134129

130+
// Remove the native select down arrow and replace it with material design arrow
135131
select.mat-input-element {
132+
&::-ms-expand {
133+
display: none;
134+
}
136135
-moz-appearance: none;
137136
-webkit-appearance: none;
138137
position: relative;

src/lib/input/input.spec.ts

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -443,19 +443,19 @@ describe('MatInput without forms', () => {
443443
fixture.detectChanges();
444444

445445
const formFieldEl =
446-
fixture.debugElement.query(By.css('.mat-form-field')).nativeElement;
447-
const inputEl = fixture.debugElement.query(By.css('select')).nativeElement;
446+
fixture.debugElement.query(By.css('.mat-form-field')).nativeElement;
447+
const selectEl = fixture.debugElement.query(By.css('select')).nativeElement;
448448

449449
expect(formFieldEl.classList.contains('mat-form-field-disabled'))
450-
.toBe(false, `Expected form field not to start out disabled.`);
451-
expect(inputEl.disabled).toBe(false);
450+
.toBe(false, `Expected form field not to start out disabled.`);
451+
expect(selectEl.disabled).toBe(false);
452452

453453
fixture.componentInstance.disabled = true;
454454
fixture.detectChanges();
455455

456456
expect(formFieldEl.classList.contains('mat-form-field-disabled'))
457-
.toBe(true, `Expected form field to look disabled after property is set.`);
458-
expect(inputEl.disabled).toBe(true);
457+
.toBe(true, `Expected form field to look disabled after property is set.`);
458+
expect(selectEl.disabled).toBe(true);
459459
}));
460460

461461
it('supports the required attribute as binding', fakeAsync(() => {
@@ -476,14 +476,14 @@ describe('MatInput without forms', () => {
476476
const fixture = createComponent(MatInputSelect);
477477
fixture.detectChanges();
478478

479-
const inputEl = fixture.debugElement.query(By.css('select')).nativeElement;
479+
const selectEl = fixture.debugElement.query(By.css('select')).nativeElement;
480480

481-
expect(inputEl.required).toBe(false);
481+
expect(selectEl.required).toBe(false);
482482

483483
fixture.componentInstance.required = true;
484484
fixture.detectChanges();
485485

486-
expect(inputEl.required).toBe(true);
486+
expect(selectEl.required).toBe(true);
487487
}));
488488

489489
it('supports the type attribute as binding', fakeAsync(() => {
@@ -646,7 +646,7 @@ describe('MatInput without forms', () => {
646646
fixture.detectChanges();
647647

648648
const formFieldEl = fixture.debugElement.query(By.css('.mat-form-field'))
649-
.nativeElement;
649+
.nativeElement;
650650
expect(formFieldEl.classList).toContain('mat-form-field-should-float');
651651
}));
652652

@@ -1339,7 +1339,7 @@ function createComponent<T>(component: Type<T>,
13391339
@Component({
13401340
template: `
13411341
<mat-form-field>
1342-
<input matInput id="test-id" placeholder="test">
1342+
<input matNativeControl id="test-id" placeholder="test">
13431343
</mat-form-field>`
13441344
})
13451345
class MatInputWithId {}
@@ -1546,7 +1546,8 @@ class MatInputWithDynamicLabel {
15461546
@Component({
15471547
template: `
15481548
<mat-form-field>
1549-
<textarea matInput [rows]="rows" [cols]="cols" [wrap]="wrap" placeholder="Snacks"></textarea>
1549+
<textarea matNativeControl [rows]="rows" [cols]="cols" [wrap]="wrap" placeholder="Snacks">
1550+
</textarea>
15501551
</mat-form-field>`
15511552
})
15521553
class MatInputTextareaWithBindings {
@@ -1763,7 +1764,7 @@ class AutosizeTextareaInAStep {}
17631764
@Component({
17641765
template: `
17651766
<mat-form-field>
1766-
<select matInput id="test-id" [disabled]="disabled" [required]="required">
1767+
<select matNativeControl id="test-id" [disabled]="disabled" [required]="required">
17671768
<option value="volvo">Volvo</option>
17681769
<option value="saab">Saab</option>
17691770
<option value="mercedes">Mercedes</option>
@@ -1779,7 +1780,7 @@ class MatInputSelect {
17791780
@Component({
17801781
template: `
17811782
<mat-form-field>
1782-
<select matInput>
1783+
<select matNativeControl>
17831784
<option value="" disabled selected></option>
17841785
<option value="saab">Saab</option>
17851786
<option value="mercedes">Mercedes</option>
@@ -1792,7 +1793,7 @@ class MatInputSelectWithNoLabelNoValue {}
17921793
@Component({
17931794
template: `
17941795
<mat-form-field>
1795-
<select matInput>
1796+
<select matNativeControl>
17961797
<option value="" label="select a car"></option>
17971798
<option value="saab">Saab</option>
17981799
<option value="mercedes">Mercedes</option>
@@ -1805,7 +1806,7 @@ class MatInputSelectWithLabel {}
18051806
@Component({
18061807
template: `
18071808
<mat-form-field>
1808-
<select matInput>
1809+
<select matNativeControl>
18091810
<option value="">select a car</option>
18101811
<option value="saab">Saab</option>
18111812
<option value="mercedes">Mercedes</option>

src/lib/input/input.ts

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,8 @@ export const _MatInputMixinBase = mixinErrorState(MatInputBase);
5858

5959
/** Directive that allows a native input to work inside a `MatFormField`. */
6060
@Directive({
61-
selector: `input[matInput], textarea[matInput], select[matControl]`,
61+
selector: `input[matInput], textarea[matInput], select[matNativeControl],
62+
input[matNativeControl], textarea[matNativeControl]`,
6263
exportAs: 'matInput',
6364
host: {
6465
/**
@@ -356,12 +357,12 @@ export class MatInput extends _MatInputMixinBase implements MatFormFieldControl<
356357
*/
357358
get shouldLabelFloat(): boolean {
358359
if (this._isNativeSelect) {
359-
// For multi select, float mat input label
360-
// If single select has value or has a option label or html, float mat input label to avoid
361-
// mat input label to overlap with the select content.
362-
const selectElement = this._elementRef.nativeElement;
363-
return selectElement.multiple || !this.empty || selectElement.options[0].label
364-
|| this.focused;
360+
// For a single-selection `<select>`, the label should float when the selected option has
361+
// a non-empty display value. For a `<select multiple>`, the label *always* floats to avoid
362+
// overlapping the label with the options.
363+
const selectElement = this._elementRef.nativeElement;
364+
return selectElement.multiple || !this.empty || selectElement.options[0].label ||
365+
this.focused;
365366
} else {
366367
return this.focused || !this.empty;
367368
}

src/lib/select/select.md

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,13 @@ To add options to the select, add `<mat-option>` elements to the `<mat-select>`.
88
has a `value` property that can be used to set the value that will be selected if the user chooses
99
this option. The content of the `<mat-option>` is what will be shown to the user.
1010

11-
Angular Material also supports use of native `<select>` element inside of
11+
Angular Material also supports use of the native `<select>` element inside of
1212
`<mat-form-field>`. The native control has several performance, accessibility,
1313
and usability advantages. See [the documentation for
1414
form-field](https://material.angular.io/components/form-field) for more information.
1515

16-
To use native select inside `<mat-form-field>`, add `matInput` as an attribute to native html select.
16+
To use a native select inside `<mat-form-field>`, add the `matNativeControl` attribute
17+
to the `<select>` element.
1718

1819
<!-- example(select-overview) -->
1920

@@ -52,7 +53,7 @@ In some cases that `<mat-form-field>` may use the placeholder as the label (see
5253
### Disabling the select or individual options
5354

5455
It is possible to disable the entire select or individual options in the select by using the
55-
disabled property on the `<select>` or `<mat-select>` and the `<option>` or <mat-option>` components respectively.
56+
disabled property on the `<select>` or `<mat-select>` and the `<option>` or <mat-option>` elements respectively.
5657

5758
<!-- example(select-disabled) -->
5859

@@ -78,7 +79,9 @@ by setting the `multiple` property. This will allow the user to select multiple
7879
using the `<mat-select>` in multiple selection mode, its value will be a sorted list of all selected
7980
values rather than a single value.
8081

81-
Multiple select with `<select multiple>` is not recommended.
82+
Using multiple selection with a native select element (`<select multiple>`) is discouraged
83+
inside `<mat-form-field>`, as the inline listbox appearance is inconsistent with other
84+
Material Design components.
8285

8386
<!-- example(select-multiple) -->
8487

@@ -144,7 +147,7 @@ The `<mat-select>` component without text or label should be given a meaningful
144147

145148
The `<mat-select>` component has `role="listbox"` and options inside select have `role="option"`.
146149

147-
The `<select>` offers better accessibility by supporting all the native html accessibility capability.
150+
The native `<select>` offers the best accessibility because it is supported directly by screen-readers.
148151

149152
### Troubleshooting
150153

src/material-examples/select-disabled/select-disabled-example.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ <h4>mat-select</h4>
1313

1414
<h4>native html select</h4>
1515
<mat-form-field>
16-
<select matControl placeholder="Choose an option" [disabled]="disableSelect.value">
16+
<select matNativeControl placeholder="Choose an option" [disabled]="disableSelect.value">
1717
<option value="" disabled selected></option>
1818
<option value="volvo">Volvo</option>
1919
<option value="saab" disabled>Saab</option>

src/material-examples/select-error-state-matcher/select-error-state-matcher-example.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ <h4>mat-select</h4>
1414

1515
<h4>native html select</h4>
1616
<mat-form-field class="demo-full-width">
17-
<select matControl placeholder="Choose one" [formControl]="nativeSelectFormControl" [errorStateMatcher]="matcher">
17+
<select matNativeControl placeholder="Choose one" [formControl]="nativeSelectFormControl" [errorStateMatcher]="matcher">
1818
<option value=""></option>
1919
<option value="valid" selected>Valid option</option>
2020
<option value="invalid">Invalid option</option>

0 commit comments

Comments
 (0)