6

I'm trying to customize mat-select with multiple checkboxes. for some reason the panel get wrong min-width as below:

enter image description here

and I don't know where its calculating this min-width. also I tried to add panelClass and override the min-width from this class, for example:

<mat-select #multipleSelect (selectionChange)="selectItem($event.value)" panelClass="multiple-panel" multiple>      

&.multiple-panel {
   min-width: 200px !important;
}

but when opening the dropdown its open with the original width (like in the pic) and after few millisecond"jump" to the custom min-width defined on the panel class.

I find the mat-select very hard to style. anybody knows how to solve this problem?

Tomer Aronovsky
  • 115
  • 2
  • 2
  • 9

6 Answers6

8

You can style your mat-select dialog box by giving a panel class (as you mentioned).
Please follow this demo : https://stackblitz.com/edit/angular-matselect-style?file=src/styles.css
to see the styled mat-select components.

Reason :

  • Reason for the delay is that angular for dialog-boxes, create a cdk-overlay-pane inside the cdk-overlay-container container, So in case of mat-select it provides a min-width of 180px, which is overridden by our panel class in the slight delay.
  • Yes, there is a slight delay in opening of dialog box and customizing its width to the specified width provided in the panel class. But the delay is acceptable in the project that i was working on.
    So, you can find the demo for styling the mat-select component, as i have provided 2 components and you can modify any css properties.
  • Try to use styles using ::ng-deep or :host >>>, if not finding any luck,
    please paste the styles in style.css.


Update 1 :
Tried css animations, and opacity for making smooth opening of the mat-select options.

.panel-class-applied-on-mat-select {
  animation-name: opacityDelay !important;
  animation-duration: 0.3s !important;
}

@keyframes opacityDelay {
   0%   {opacity: 0;}
  25%  {opacity: 0;}
  50%  {opacity: 0;}
  75%  {opacity: 0;}
  100% {opacity: 1;}
}

Updated StackBlitz Demo

Abhishek Kumar
  • 2,501
  • 10
  • 25
  • Hmmm... it is not acceptable for my project. It sucks there isn't a better solution. – cheesydoritosandkale Dec 26 '18 at 16:54
  • @cheesydoritosandkale see the updated answer, if its helpful because the opening is delayed and made smooth, and mat-select options are now opening correctly to the expected width. – Abhishek Kumar Dec 27 '18 at 06:40
  • @AbhishekKumar Amazing idea. work for me. but you support opening the panel only. on close its get bigger again for a second, how do you recommend to add the delay when closing the panel? – Tomer Aronovsky Dec 28 '18 at 08:13
  • @AbhishekKumar ? – Tomer Aronovsky Jan 06 '19 at 23:01
  • @TomerAronovsky my answer supports opening of panel as i have applied animation with the panelClass provided, because on closing panelClass animation will not work. The animation will work correctly if on opening the panel a class should be added with animation property, and on closing that class should be removed. In this case animation will work perfectly fine. So i tried the open and close events, also some other events given on the official docs of mat-select but was no luck getting handlers on opening and closing of mat-select. – Abhishek Kumar Jan 07 '19 at 00:38
  • @TomerAronovsky sorry for not replying earlier as i forgot to reply on this thread after trying to implement opening and closing events on the mat-select. – Abhishek Kumar Jan 07 '19 at 00:39
  • I will have to try your solution. I ended up fixing it by just adding .mat-select-panel { margin-right: -32px; } Which works pretty well. – cheesydoritosandkale Jan 11 '19 at 15:35
5

I used another approach. Just added this piece of code to global style.

.mat-select-panel {
// some your code
  &.ng-animating {
       visibility: hidden;
    }
  }

You can try this solution on DEMO StackBlitz.
Hack with opacity did not fix jumping width when select is closing.

3

Please go easy on me S.O. This is my first time contributing. :)

After debugging the console, and running into this issue. Solutions were not clear online. So I'm posting mine here in case someone else runs into this.

I found that there is a width permanently set for the infix class. If you unset it, and optionally add some padding to the right of the value, you'll find that will resolve the issue. Add :host for encapsulation when using ::ng-deep.

Important to Note: ::ng-deep is being permanently deprecated after Angular v14. There is a property in the @Component() annotation called encapsulation which can be used to turn off the view encapsulation for the component instead of using ::ng-deep.

Solution for the deprecation of ::ng-deep:

@Component({
  selector: 'app-selector-name',
  template: `<div>Hello World!</div>`,
  encapsulation: ViewEncapsulation.None,
  styles: [
    `
      :host mat-form-field .mat-form-field-infix {
        width: unset;
      }
      :host mat-form-field .mat-select-value {
        padding-right: 0.5rem; /* 8px */ 
        /* Alternatively, for TailwindCSS: @apply pr-2 */
      }
      :host .random-class {
         /* some encapsulated styling... */
      }
      .another-random-class {
         /* some non-encapsulated styling... */
      }
    `
  ]
})

Solution if you do not care about the deprecation of ::ng-deep:

      :host ::ng-deep mat-form-field .mat-form-field-infix {
        width: unset;
      }
      :host ::ng-deep mat-form-field .mat-select-value {
        padding-right: 0.5rem; /* 8px */
      }
Omie Walls
  • 73
  • 7
  • ::ng-deep has been deprecated for a long time, but there is still no recommended alternative, and there doesn't seem to be a known EOL. You can track this here: https://github.com/angular/angular/issues/25160 – JWess Apr 14 '23 at 17:58
1

You'll need to change viewEncapsulation to none at your component decorator.and then add following css to remove the transition effect.Have a look at viewencapsulation in angular docs https://angular.io/guide/component-styles#view-encapsulation.

@Component({
selector: 'app-selector',
templateUrl: './template.html',
styleUrls: ['./template.css'],
encapsulation: ViewEncapsulation.None
})
//CSS
.cdk-overlay-connected-position-bounding-box .cdk-overlay-pane .mat-select-panel.ng-animating {
display: none;
}
1

I was also facing the same issue and now found the solution that fit perfectly for me. Try setting min width of the panel with ::ng-deep like this.

::ng-deep .mat-select-panel {
  min-width: calc(100% + 14px) !important;
}

This worked for me.

Apurva Pathak
  • 692
  • 1
  • 9
  • 22
0

Try this way : define a panel class for your mat-select in the code and then in the global/app styling file just add:

.panel-class-name .mat-select-panel {
 // add your styling here
}

It worked for me to add some component specific styling for material components.