-
Notifications
You must be signed in to change notification settings - Fork 6.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(form-field): support native select element #12707
Conversation
src/lib/form-field/form-field.md
Outdated
@@ -8,6 +8,7 @@ In this document, "form field" refers to the wrapper component `<mat-form-field> | |||
|
|||
The following Angular Material components are designed to work inside a `<mat-form-field>`: | |||
* [`<input matInput>` & `<textarea matInput>`](https://material.angular.io/components/input/overview) | |||
* [`<select matInput>`](https://material.angular.io/components/select/overview) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be <select matNativeSelect>
?
(here and elsewhere)
Now that I'm thinking about it, we could deprecate matInput
and make the selector matControl
work for both... @mmalerba thoughts?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe matFormControl
for consistency with mat-form-field
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd like it to be something short, matInput
,matSelect
, and matControl
are all fine by me
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
after team discussion, decided to go with matNativeControl
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Still need to update these lines
src/lib/input/input.scss
Outdated
// Remove select button from IE11 | ||
select::-ms-expand { | ||
display: none; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will target all <select>
elements; it should be restricted to a CSS class that's applied by the directive
src/lib/input/input.scss
Outdated
display: none; | ||
} | ||
|
||
select[matInput] { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Prefer CSS class selectors to attribute selectors
src/lib/input/input.scss
Outdated
-webkit-appearance: none; | ||
position: relative; | ||
background-color: transparent; | ||
background-image: url('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'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you extract the uri portion of this into a sass variable with a comment explaining what it is?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
AFAIK we can't use data URIs in CSS. See #8898.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We couldn't think of another way to do this, so we checked directly with Google's security team. They said that they see no reason to ban data:
URIs, so we can relax this restriction. I do want to add documentation that talks about our CSP support.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
security team approved using data URI for image.
src/lib/input/input.scss
Outdated
background-repeat: no-repeat; | ||
display: inline-flex; | ||
box-sizing: border-box; | ||
background-position: right center; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this need to be flipped in RTL?
src/lib/input/input.ts
Outdated
} | ||
} | ||
|
||
private shouldLabelFloatForSelect(selectElement:HTMLSelectElement): boolean { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Space after colon
src/lib/input/input.ts
Outdated
} | ||
} | ||
|
||
private shouldLabelFloatForSelect(selectElement:HTMLSelectElement): boolean { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This method should be prefixed with an underscore (applies to any non-public api)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we should have another class only with the select functionality that extends MatInput
? Otherwise we'll end up sprinkling if (isSelect)
checks everywhere.
src/lib/select/select.md
Outdated
@@ -1,8 +1,11 @@ | |||
Angular material supports both native html select and `<mat-select>` to work inside a |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would leave the original text for this file the same, and then add a new paragraph underneath that says something like
Angular Material also supports use of native the `<select>` element inside of
`<mat-form-field>`. The native control has several performance, accessibility,
and usability advantages. See [the documentation for
form-field](https://material.angular.io/components/form-field) for more information.
src/lib/select/select.md
Outdated
@@ -71,11 +74,13 @@ by setting the `multiple` property. This will allow the user to select multiple | |||
using the `<mat-select>` in multiple selection mode, its value will be a sorted list of all selected | |||
values rather than a single value. | |||
|
|||
Multiple select with `<select>` is not recommended. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would specifically use <select multiple>
here
src/lib/form-field/form-field.md
Outdated
@@ -8,6 +8,7 @@ In this document, "form field" refers to the wrapper component `<mat-form-field> | |||
|
|||
The following Angular Material components are designed to work inside a `<mat-form-field>`: | |||
* [`<input matInput>` & `<textarea matInput>`](https://material.angular.io/components/input/overview) | |||
* [`<select matInput>`](https://material.angular.io/components/select/overview) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe matFormControl
for consistency with mat-form-field
?
src/lib/input/input.scss
Outdated
-webkit-appearance: none; | ||
position: relative; | ||
background-color: transparent; | ||
background-image: url('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'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
AFAIK we can't use data URIs in CSS. See #8898.
src/lib/input/input.spec.ts
Outdated
@@ -572,6 +614,41 @@ describe('MatInput without forms', () => { | |||
expect(formFieldEl.classList).toContain('mat-form-field-should-float'); | |||
})); | |||
|
|||
it('should floating labels when select has value', fakeAsync(() => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"should floating" -> "should float"
src/lib/input/input.spec.ts
Outdated
expect(formFieldEl.classList).toContain('mat-form-field-should-float'); | ||
})); | ||
|
||
it('should not floating labels when select has no value, no option label, ' + |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
floating -> float
src/lib/input/input.ts
Outdated
@@ -351,7 +350,26 @@ export class MatInput extends _MatInputMixinBase implements MatFormFieldControl< | |||
* Implemented as part of MatFormFieldControl. | |||
* @docs-private | |||
*/ | |||
get shouldLabelFloat(): boolean { return this.focused || !this.empty; } | |||
get shouldLabelFloat(): boolean { | |||
if (this._elementRef.nativeElement.nodeName.toLowerCase() === 'select') { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of doing this in a getter, the check can be done in the constructor since the element's nodeName
won't change.
src/lib/input/input.ts
Outdated
} | ||
} | ||
|
||
private shouldLabelFloatForSelect(selectElement:HTMLSelectElement): boolean { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we should have another class only with the select functionality that extends MatInput
? Otherwise we'll end up sprinkling if (isSelect)
checks everywhere.
src/lib/input/input.ts
Outdated
if (selectElement.multiple) { | ||
// For multi select, float mat input label | ||
return true; | ||
} else if (!this.empty || selectElement.options[0].label || selectElement.options[0].innerHTML) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since this is being called in a getter, it can be very expensive to keep checking innerHTML
. We should either move away from checking the DOM or check textContent
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we can just use label to cover both. from the documentation "label
This attribute is text for the label indicating the meaning of the option. If the label attribute isn't defined, its value is that of the element text content."
And testing confirmed that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this method can be simplified into one statement:
return selectedElement.multiple || this.focused || !this.empty ||
selectElement.options[0].label || selectElement.options[0].innerHTML;
src/lib/select/select.md
Outdated
Angular material supports both native html select and `<mat-select>` to work inside a | ||
[`<mat-form-field>`] element.(https://material.angular.io/components/form-field/overview) element. | ||
|
||
To use native select inside `<mat-form-field>`, add `matInput` as a attribute to native html select. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"as a" -> "as an"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
addressed review comments.
After team discussion, decided to go with matNativeControl for input, textarea and select. Changed the existing input and textarea to use matNativeControl in a few places to make sure both matInput and matNativeControl works for input/textarea.
Hi @vivian-hu! This PR has merge conflicts due to recent upstream merges. |
src/lib/input/input.scss
Outdated
display: none; | ||
} | ||
|
||
//encoded material design select arrow svg |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Comment should have a spacer after //
and start with a capital letter:
// Drowndown arrow svg icon, url-encoded.
src/lib/input/input.scss
Outdated
$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'; | ||
/* stylelint-enable */ | ||
|
||
select.mat-input-element { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add a comment here that explains what this class is doing.
src/lib/input/input.ts
Outdated
// For multi select, float mat input label | ||
// If single select has value or has a option label or html, float mat input label to avoid | ||
// mat input label to overlap with the select content. | ||
const selectElement = this._elementRef.nativeElement; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Extra space
src/lib/input/input.ts
Outdated
if (this._isNativeSelect) { | ||
// For multi select, float mat input label | ||
// If single select has value or has a option label or html, float mat input label to avoid | ||
// mat input label to overlap with the select content. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Line-break and capitalization is off. Also, should this say "For native select" instead of "For multi select"?
src/lib/input/input.ts
Outdated
// mat input label to overlap with the select content. | ||
const selectElement = this._elementRef.nativeElement; | ||
return selectElement.multiple || !this.empty || selectElement.options[0].label | ||
|| this.focused; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Prefer putting the operator on the previous line:
return selectElement.multiple || !this.empty || selectElement.options[0].label ||
this.focused;
src/lib/select/select.md
Outdated
and usability advantages. See [the documentation for | ||
form-field](https://material.angular.io/components/form-field) for more information. | ||
|
||
To use native select inside `<mat-form-field>`, add `matInput` as an attribute to native html select. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Update selector here
src/lib/select/select.md
Outdated
The select component has `role="listbox"` and options inside select have `role="option"`. | ||
The `<mat-select>` component has `role="listbox"` and options inside select have `role="option"`. | ||
|
||
The `<select>` offers better accessibility by supporting all the native html accessibility capability. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would rephrase this
The native `<select>` offers the best accessibility because it is supported directly by screen-readers.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
addressed code review comments.
src/lib/form-field/form-field.md
Outdated
@@ -8,6 +8,7 @@ In this document, "form field" refers to the wrapper component `<mat-form-field> | |||
|
|||
The following Angular Material components are designed to work inside a `<mat-form-field>`: | |||
* [`<input matInput>` & `<textarea matInput>`](https://material.angular.io/components/input/overview) | |||
* [`<select matInput>`](https://material.angular.io/components/select/overview) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Still need to update these lines
src/lib/form-field/form-field.md
Outdated
@@ -41,7 +42,8 @@ want a floating label, add a `<mat-label>` to the `mat-form-field`. | |||
### Floating label | |||
|
|||
The floating label is a text label displayed on top of the form field control when | |||
the control does not contain any text. By default, when text is present the floating label | |||
the control does not contain any text or when `<select matInput>` does not show any option text. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Still needs updated selector
src/lib/input/input.scss
Outdated
// Remove select button from IE11 | ||
select.mat-input-element::-ms-expand { | ||
display: none; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can move this into the rule below like this:
select.mat-input-element {
&::-ms-expand {
display: none;
}
-moz-appearance: none;
...
}
src/lib/input/input.spec.ts
Outdated
|
||
const formFieldEl = | ||
fixture.debugElement.query(By.css('.mat-form-field')).nativeElement; | ||
const inputEl = fixture.debugElement.query(By.css('select')).nativeElement; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
inputEl
-> selectElement
(or selectEl
) here and other places where it is a select
element and not an input
src/lib/input/input.ts
Outdated
if (this._isNativeSelect) { | ||
// If multi select, float mat-label. | ||
// If single select with value, with an option label or html, float mat-label to avoid | ||
// it overlapping with select content. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about
// For a single-selection `<select>`, the label should float when the selected option has a non-empty
// display value. For a `<select multiple>`, the label *always* floats to avoid overlapping the label
// with the options.
src/lib/select/select.md
Outdated
and usability advantages. See [the documentation for | ||
form-field](https://material.angular.io/components/form-field) for more information. | ||
|
||
To use native select inside `<mat-form-field>`, add `matNativeControl` as an attribute to native html select. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To use a native select inside `<mat-form-field>`, add the `matNativeControl` attribute
to the `<select>` element.
src/lib/select/select.md
Outdated
@@ -45,7 +52,7 @@ In some cases that `<mat-form-field>` may use the placeholder as the label (see | |||
### Disabling the select or individual options | |||
|
|||
It is possible to disable the entire select or individual options in the select by using the | |||
disabled property on the `<mat-select>` and the `<mat-option>` components respectively. | |||
disabled property on the `<select>` or `<mat-select>` and the `<option>` or <mat-option>` components respectively. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Change components
here to elements
since <option>
is not a component.
src/lib/select/select.md
Outdated
@@ -71,11 +78,13 @@ by setting the `multiple` property. This will allow the user to select multiple | |||
using the `<mat-select>` in multiple selection mode, its value will be a sorted list of all selected | |||
values rather than a single value. | |||
|
|||
Multiple select with `<select multiple>` is not recommended. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about
Using multiple selection with a native select element (`<select multiple>`) is discouraged
inside `<mat-form-field>`, as the inline listbox appearance is inconsistent with other
Material Design components.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Update based on review feedback
src/lib/form-field/form-field.md
Outdated
@@ -8,6 +8,7 @@ In this document, "form field" refers to the wrapper component `<mat-form-field> | |||
|
|||
The following Angular Material components are designed to work inside a `<mat-form-field>`: | |||
* [`<input matInput>` & `<textarea matInput>`](https://material.angular.io/components/input/overview) | |||
* [`<select matNativeControl>`](https://material.angular.io/components/select/overview) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should also update the line above:
<input matNativeControl>
and <textarea matNativeControl>
src/lib/input/input.spec.ts
Outdated
fixture.detectChanges(); | ||
|
||
const formFieldEl = | ||
fixture.debugElement.query(By.css('.mat-form-field')).nativeElement; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just noticed this, but line overflow indent should be +4 rather than +2
(here and elsewhere)
src/lib/select/select.md
Outdated
@@ -8,6 +8,14 @@ To add options to the select, add `<mat-option>` elements to the `<mat-select>`. | |||
has a `value` property that can be used to set the value that will be selected if the user chooses | |||
this option. The content of the `<mat-option>` is what will be shown to the user. | |||
|
|||
Angular Material also supports use of native `<select>` element inside of |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
of native `<select>` element
-> of the native `<select>` element
75b57d4
to
47fcaf8
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed indentation and updated selector name for input and textarea.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
Commit message should be:
|
Hi @vivian-hu! This PR has merge conflicts due to recent upstream merges. |
63f07ca
to
4e04c81
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
changed the way to set "Readonly" attribute.
This issue has been automatically locked due to inactivity. Read more about our automatic conversation locking policy. This action has been performed automatically by a bot. |
No description provided.