How to change toggle icon of mat-expansion-panel?

Viewed 21922

The default icon for toggling a mat-expansion-panel is >. Setting hideToggle true just hides the toggle icon. Is there any way to change it? I found nothing in the official documentation. I want to use + or - icon if the state is closed or opened respectively.

6 Answers

As stated on the Angular Material Expansion Panel documentation, we can customise the stylings of the mat-extension-panel-header, which will in turn allow you to customise the icons.

First and foremost, you hide the original icon by setting the hideToggle attribute to true. In addition, we assign the event bindings (opened) and (closed) to the panelOpenState property. You may check out the other properties of mat-expansion-panel over here.

<mat-expansion-panel (opened)="panelOpenState = true" (closed)="panelOpenState = false"hideToggle="true">

Next, on your mat-panel-description, you include the custom icons required. The icons shown will be dependent on the state of the panel. For this example, we are using the icons from Material Icons.

<mat-panel-description>
  <mat-icon *ngIf="!panelOpenState">add</mat-icon>
  <mat-icon *ngIf="panelOpenState">remove</mat-icon>
</mat-panel-description> 

I have edited the original sample from the Angular documentation, such that it is using the custom + and minus icons to denote the expanded/collapsed state of the mat-extension-panel. You may access the demo over here.

There is a class .mat-expanded which is applied to a <mat-expansion-panel>

So you can just use CSS to change the icon, no JS required.

  • To change arrow down to up:
.mat-expanded .mat-expansion-panel-header-title .material-icons{
  transform: rotate(180deg);
}
    <mat-panel-title>
      <span class="material-icons">expand_more</span>
      Panel with icon `transform`
    </mat-panel-title>
  • To swap icons:
.mat-expansion-panel-header-title .open,
.mat-expanded .mat-expansion-panel-header-title .close{
  display: inline-block;
}
.mat-expanded .mat-expansion-panel-header-title .open,
.mat-expansion-panel-header-title .close{
  display: none;
}
    <mat-panel-title>
      <span class="material-icons open">open_in_full</span>
      <span class="material-icons close">close_fullscreen</span>
      Panel with open/close
    </mat-panel-title>

Here is a link to a demo https://stackblitz.com/edit/angular-e2fnlm

CSS solution works when you have multiple Material Expansion Panels

Give the name to the mat-expansion-panel say panel in the example. Use expanded property of the mat-expansion-panel to show or hide the + or - icon.

 <mat-expansion-panel #panel  hideToggle>
        <mat-expansion-panel-header>
             <mat-panel-title>
                        Buttons
             </mat-panel-title>
             <mat-icon >{{panel.expanded? 'remove' : 'add'}}</mat-icon>
                        
        </mat-expansion-panel-header>
                   
  </mat-expansion-panel>

For those interested, here is an example that works with multiple Expansion Panels:

View:

<mat-accordion>
  <mat-expansion-panel *ngFor="let panel of panels; let i = index"
      (opened)="panelOpenState[i] = true" (closed)="panelOpenState[i] = false"
      hideToggle>
    <mat-expansion-panel-header>
      <mat-panel-title>
        {{panel.title}}
      </mat-panel-title>
      <span *ngIf="!panelOpenState[i]">Show</span>
      <span *ngIf="panelOpenState[i]">Hide</span>
    </mat-expansion-panel-header>

    Panel Content
  </mat-expansion-panel>
</mat-accordion>

Component:

export class PanelComponent implements OnInit {
  panels: [];
  panelOpenState: boolean[] = [];

  ngOnInit() {
    // loop to add panels
    for (let i = 0; i < 5; i++) {
      this.panels.push({ title: i });
      this.panelOpenState.push(false);
    }
  }
}

You can use mat-icon in the mat-expansion-panel-header.

Please check this working example on stackblitz.

For a + icon you can use <mat-icon>add</mat-icon>

<mat-accordion>
  <mat-expansion-panel hideToggle>
    <mat-expansion-panel-header>
      <mat-panel-title>
        Personal data
      </mat-panel-title>
      <mat-icon>add</mat-icon>
  </mat-expansion-panel-header>

  <mat-form-field>
      <input matInput placeholder="First name">
  </mat-form-field>

  <mat-form-field>
     <input matInput placeholder="Age">
  </mat-form-field>
</mat-expansion-panel>

add hideToggle to mat-expansion-panel :

<mat-expansion-panel (opened)="panelOpenState = true"
                             (closed)="panelOpenState = false" hideToggle>

and add icon:

 <mat-expansion-panel-header>
            <mat-icon>add</mat-icon>
Related