3
votes

I am using the material select element mat-select in my application. I want to load the option list just below the select field, like a regular select box and not as a overlay style give. For that I have applied the below style to given select element.

             <mat-form-field>
                  <mat-select [formControlName]="input1">
                        <mat-option>None</mat-option>
                        <mat-option *ngFor="let opt_value of  input1.enumNames; let i = index" value="{{input1.enum[i]}}" >{{opt_value}}</mat-option>
                  </mat-select>

             </mat-form-field>   

Here is the style that I applied after inspecting the responsible element.

.mat-select-panel {
   transform: translate(-2px, 44px) !important;
  font-family: Lato,sans-serif;

}

Now when I click the first time on the select field, The options list loads as desired, just below the select field. Like this...

enter image description here

But after selecting any option (except than 'none') if I again click on the field to change the option, the option list load as old material style like this and hide my select field somewhere behind yellow highlight.

enter image description here

How to style Mat-options or mat-select-panel correctly so that I always get the result as per the first image.

4

4 Answers

9
votes

Use disableOptionCentering attribute of mat-select. https://material.angular.io/components/select/api

4
votes

I think the position of the mat-option list is dynamically determined. I used panelClass="testClass" and disableOptionCentering properties in mat-select.

<mat-select placeholder="Select a movie" disableOptionCentering panelClass="testClass">
   <mat-option *ngFor="let movie of movies" [value]="movie">
     {{movie}}
   </mat-option>
</mat-select>

Also, added this style class in my style.scss file:

.testClass{
  margin-top: 35px;
  margin-bottom: 30px;
}

It worked fine for my app!

3
votes

This experience is prescribed by Material Design.

Menus are positioned over their emitting elements such that the currently selected menu item appears on top of the emitting element.

The first question you should ask yourself is "why do I want/need to change that experience?" For a Material Design application, it is the correct user experience.

You can modify the mat-select-panel class's position as already suggested, but there are three technical problems with that approach, in addition to being against Material Design guidelines.

First, the panel is dynamically inserted into the DOM when the list is opened, and it is not a child of it's mat-select element, so if you have more than one select component, they will all be affected the same way. However, you can get around that problem by using the panelClass property of mat-select.

Second, the "offset" amount that would be needed depends on the size of the panel (related to number of items and window size) and the index of the selected item. Adjusting the position by a fixed a distance will not produce the desired result all of the time. You would need to know specifically how many other items appear above the selected item, and multiply that number by the offset amount for one item (e.g. 48px - the standard height of selection list items).

Third, the position of the panel is dynamically determined so that when the select field is near the bottom of the window such that there is not enough room to display it below the field, the panel is displayed above the field instead. So adjusting the position of the panel downward will only work when there is room for the panel below the field. While you might be able to get away with that most of the time, it is nothing more than a hack that will probably fail eventually.

If you can solve all of those problems in a predictable, reliable fashion (not a hack), please post your code here - I'm sure others would benefit from it.

A better solution might be to create your own custom select control based on the menu component which allows for custom positioning.

1
votes

You can modify your CSS to use a margin:

.mat-select-panel {
  margin-top: 45px;
}

It works fine for me in this example.