cssangularsassangular-materialmaterial3

How do I change the arrow color in mat select without ng-deep or global styles - Angular Material 19


My requirement is simple, I want to change the arrow inside mat-select to a different color.

Below are the solutions known, but I do not want to implement.

  1. Using ::ng-deep to customize the arrow.
  2. Using global-styles.scss to define a class to customize the arrow.

The problem with the two approaches is that, during material upgrade I have to rework the customizations as mentioned in the docs.

Direct Styles Overrrides

Below is the code I have tried. The solution is using ::ng-deep which I do not want.

SCSS:

:host ::ng-deep {
  mat-select .mat-mdc-select-arrow {
    color: red !important;
  }
}

HTML:

<h4>Basic mat-select</h4>
<mat-form-field>
  <mat-label>Favorite food</mat-label>
  <mat-select>
    @for (food of foods; track food) {
    <mat-option [value]="food.value">{{food.viewValue}}</mat-option>
    }
  </mat-select>
</mat-form-field>

Stackblitz Demo


Solution

  • As of Angular Material 19, we might have less use of :ng-deep to apply CSS to nested element.

    This is because of the introduction of the new mat.<<component-type>>-overrides(( ... )) API, we can customize the CSS properties used to style the material elements.

    Since CSS properties are not affected by view encapsulation, we can easily apply the styling to any element of the mat-select, provided the supporting variable is available for customization.

    Firstly visit the styling tab of the component to customize.

    Mat Select Styling Tab - Docs

    Then choose the customization, then apply it to the scss file of the component.

    @use '@angular/material' as mat;
    
    .custom-select {
      @include mat.select-overrides(
        (
          enabled-arrow-color: red,
          disabled-arrow-color: lightred,
          focused-arrow-color: darkred,
          invalid-arrow-color: crimson,
        )
      );
    }
    

    Here I am using a class called .custom-select to apply the styling only to a particular select, we can also do :root to apply to all select elements, or scope it to just this component by a class or :host.

    Full Code:

    TS:

    import { Component } from '@angular/core';
    import { MatInputModule } from '@angular/material/input';
    import { MatSelectModule } from '@angular/material/select';
    import { MatFormFieldModule } from '@angular/material/form-field';
    import { FormsModule } from '@angular/forms';
    
    interface Food {
      value: string;
      viewValue: string;
    }
    
    interface Car {
      value: string;
      viewValue: string;
    }
    
    /**
     * @title Select in a form
     */
    @Component({
      selector: 'select-form-example',
      templateUrl: 'select-form-example.html',
      styleUrls: ['select-form-example.scss'],
      imports: [FormsModule, MatFormFieldModule, MatSelectModule, MatInputModule],
    })
    export class SelectFormExample {
      selectedValue: string;
      selectedCar: string;
    
      foods: Food[] = [
        { value: 'steak-0', viewValue: 'Steak' },
        { value: 'pizza-1', viewValue: 'Pizza' },
        { value: 'tacos-2', viewValue: 'Tacos' },
      ];
    
      cars: Car[] = [
        { value: 'volvo', viewValue: 'Volvo' },
        { value: 'saab', viewValue: 'Saab' },
        { value: 'mercedes', viewValue: 'Mercedes' },
      ];
    }
    

    HTML:

    <form>
      <h4>mat-select</h4>
      <mat-form-field class="custom-select">
        <mat-label>Favorite food</mat-label>
        <mat-select [(ngModel)]="selectedValue" name="food">
          @for (food of foods; track food) {
          <mat-option [value]="food.value">{{food.viewValue}}</mat-option>
          }
        </mat-select>
      </mat-form-field>
    </form>
    

    Stackblitz Demo