Customizing the toggle icon on mat-expansion-panel - A step-by-step guide

By default, the icon used for toggling a mat-expansion-panel is >. If you set hideToggle to true, it will simply hide the toggle icon. Is there any way to customize this icon? The official documentation doesn't provide any details. I would like to use the icons + or - to represent closed or open states respectively.

Answer №1

According to the Angular Material Expansion Panel guide, we have the ability to personalize the appearance of the mat-extension-panel-header, which in turn allows us to customize the icons.

To begin with, you can hide the default icon by setting the attribute hideToggle to true. Moreover, we assign the event bindings (opened) and (closed) to the panelOpenState property. Explore more properties of mat-expansion-panel here.

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

Next, within your mat-panel-description, include the required custom icons. The displayed icons will change based on the panel's state. In this demonstration, we are using 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 modified the original code provided by Angular documentation to showcase the usage of custom + and minus icons to represent the expanded/collapsed state of the mat-extension-panel. You can view the demo here.

Answer №2

There is a special .mat-expanded class that gets added to a <mat-expansion-panel>

You can easily customize the icon using CSS, no need for JavaScript.

  • To change the arrow direction from 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 switch between 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>

Check out this demo for a live example here

The CSS solution can be applied to multiple Material Expansion Panels

Answer №3

Name the mat-expansion-panel as "panel" in this example. Utilize the expanded property of the mat-expansion-panel to control the visibility of the +/- 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>

Answer №4

For those interested in implementing multiple Expansion Panels, here is a useful example:

Instructions:

<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 Setup:

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

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

Answer №5

Utilize the mat-icon within the mat-expansion-panel-header.

Take a look at this operational demonstration on stackblitz.

To display a + symbol, you can employ

<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>

Answer №6

This technique is effective even when iterating through a for loop alongside the mat-expansion-panel.

  1. Firstly, set your icons - such as "add" and "remove" (represented by + and -).

  2. Then, apply classes to them ('close' on add(+) if you want to display + when the panel is closed) so they appear like this:

    <mat-expansion-panel-header>
       <mat-icon class="close">add</mat-icon>
       <mat-icon class="open">remove</mat-icon>
       ...
    
  3. Add this styling in the SCSS file (adjust selector if necessary. I have the structure as shown directly under 'mat-expansion-panel-header')

    ::ng-deep mat-expansion-panel-header.mat-expanded > span > mat-icon.open {
         display: block;
     }
     ::ng-deep mat-expansion-panel-header:not(.mat-expanded) > span > mat-icon.open {
         display: none;
     }
    
     ::ng-deep mat-expansion-panel-header.mat-expanded > span > mat-icon.close {
         display: none;
     }
    
     ::ng-deep mat-expansion-panel-header:not(.mat-expanded) > span > mat-icon.close {
         display: block;
     }
    

Answer №7

Include hideToggle in mat-expansion-panel :

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

Also, don't forget to include an icon:

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

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Unit Testing Angular: Mastering Unit Testing for the .map() Function

I am in need of testing a service method, but I am unsure about how to achieve complete coverage for the code that gets executed as a result of calling another injected service method. The Service Method to be tested: @Injectable() export class BomRevisi ...

Retrieve the initial data of the AngularJS model upon button click

Previously, I was able to retrieve the initial values of the model using this.model.changed or this.model._previousAttributes in BackboneJS. Now, I am looking to achieve the same functionality in AngularJS, where I can track all changes made to the model ...

Sorting with jQuery UI - execute action on drag start and clear on drop

I am currently working with two blocks: one is "draggable" and the other is "sortable". My goal is to add a background color to a div when dragging an item from "sortable" and remove it once the dragging stops. Below is my JavaScript code: $(".sortableL ...

Inserting Text with Line Breaks into a Textarea Using jQuery and PHP MySQL

I am dealing with a form that users complete with a textarea input. This form is saved into a MySQL database, and later the user has the ability to make edits. The problem I am facing is that whenever I try to use AJAX to provide suggestions for the textar ...

Tips for effectively utilizing URLSearchParams in Angular 5 HttpClient's "get" function

When working with Angular 4.2, I used the Http service and made use of the get method by passing in a URLSearchParams object as the search parameter: this.http.get(url, {headers: this.setHeaders(), search: params}) Now I am looking to upgrade to Angular ...

Steps to automatically close a modal in Angular 7 after selecting a link within the modal

I have a modal with a link that opens another page when clicked. However, the modal does not close when the link opens a new page. Can you help me figure out how to close the modal? × Important Note We strongly advise making individual reservatio ...

What is the best way to use the cursor-pointer property in combination with a (click) event handler

<i class="cursor-pointer" (click)="sort()"></i> Our development team is grappling with numerous repetitive class definitions such as this one. I wanted to find a more efficient way to automatically add the cursor pointer style whenever a (clic ...

Issues with the Jquery feedback plugin's functionality are currently preventing it

I wanted to incorporate a feedback feature into my web application. To do this, I searched on Google and found a suitable jQuery plugin. I followed the documentation provided by the plugin, including the library in my HTML file, and then wrote the code as ...

Error: JSON parsing failed due to an unexpected character 'W' at the beginning

I am encountering an issue while sending a POST Request through the API in JavaScript. The method I have been using for multiple POST Requests is now displaying the error message: SyntaxError: Unexpected token W in JSON at position 0 Below is the snippet ...

Combining several SVG images into a single file disrupts the text

In my web app, I utilize SVG files to visually map different types of data onto our experimental dataset. Each SVG file corresponds to a specific type of data and is displayed individually on most pages of the site. These maps include tooltips on nodes for ...

Executing an Ajax request. Best method for transmitting various data elements:

I am currently attempting to perform an ajax call with multiple data inputs. When I send only one string of data, I use the following method: $.ajax({ url: "php/update_lastordning.php", type: "POST", data: "elId=" + elId }); To retrieve t ...

Tips for assigning a state variable as a new key within an object stored in another state variable in React

The initial state variable is newUser, starting as an empty string. A form includes an input field to update newUser with the input value. There are two additional state variables: users, set to {currentUser: false}, and userInfo, set to {id: "example ...

How to implement an infinite loop using Jquery

Here is an example of the HTML structure: <ul class="innerfade"> <li style="position: absolute; z-index: 4; display: none;">some Text</li> <li style="position: absolute; z-index: 3; display: none;">bla bla bla</li> & ...

Creating a custom dropdown filter in ag-grid-angular

I am currently integrating 'ag-grid-angular' into my project. https://i.sstatic.net/9jcy2.png As for the filter display, I would like to replace the search box with a drop-down menu. Furthermore, I aim to populate this drop-down with unique ele ...

JavaScript is failing to display array elements

I'm currently in the process of developing a filtering system for a festival website. The price filter is up and running smoothly, but now I'm facing a challenge with the genre filter. For the genre filter, I've created an array named filte ...

Adding Images Using Angular 8

I'm encountering difficulties with image upload in the file located at '../src/app/assets/'. Below is the Form I am using: <form [formGroup]="formRegister" novalidate=""> <div class="form-group"> <label for="ex ...

Press on a rectangle inside an HTML5 SVG program

I'm currently developing a web application that utilizes the svg and Raphael library: workflowEditor.show(); var myList = document.getElementsByTagName("rect"); for (var a = 0; a < myList.length; a++) { myList[a].addEventListener("OnClick", f ...

Is there a way to extract a variable or a cookie with multiple values in Selenium?

I need assistance in extracting a specific value from a multi-value cookie using the Selenium IDE. The cookie's Tracking Cookie Value is as follows: G=1&GS=2&UXD=MY8675309=&CC=234&SC=3535&CIC=2724624 Currently, I have stored the e ...

An error occurred suddenly while building: ReferenceError - the term "exports" is not defined in the ES module scope

Having trouble resolving this error in the Qwik framework while building a static site: ReferenceError: exports is not defined in ES module scope at file:///media/oem/MyFiles/8_DEVELOPMENT/nexasoft/server/@qwik-city-plan.mjs:1:1097 at ModuleJob. ...

What steps should I follow to enable my bot to generate or duplicate a new voice channel?

I needed my bot to either create a new voice server or clone an existing one. The variable "voic" contains the ID of the voice channel. voic.voiceChannel.clone(undefined, true, false, 'Needed a clone') // example from ...