Edupala

Comprehensive Full Stack Development Tutorial: Learn Ionic, Angular, React, React Native, and Node.js with JavaScript

How to implement Angular Material Accordion in Angular 13|14 .?

Angular material expansion panel example

An Angular material is an amazing UI for the Angular framework, it has lots of pre-built components like cards, modals, and more, and the Angular material expansion panel or Angular material accordion is one of them.

We have three objectives behind this tutorial, first will learn how to use the Angular material expansion panel component, and second how to add images. Last how to apply a style to Angular material accordion component like the background color to header. Let’s get started.

angular material accordion
Angular material accordion

What is an Angular Material Accordion?

Angular Material accordion – or we can also call Angular material expansion panel component is the same. This component is a seamless vertically collapsible panel accordion. We can group a list of related items in an accordion panel, each item in the accordion has an item header and body. Item is expanded its body only when we particular item header is clicked.

Step 1: Setup and configure the Angular Material Accordion project

Let’s first create an Angular material expansion panel project, we need to install the angular material library and we don’t have any dependency on another library. Let’s install the angular material library.

ng new matAccordionApp
cd matAccordionApp
ng add @angular/material

While running the 3rd command will ask you the select theme, material typography, and animation, press yes on all. To use the Angular material component, we have to import it into our app module. Let’s create a module and import all material components on it.

ng g m ng-material
Angular material card example

We also need to add two custom component lists and the nextPanel to demonstrate the Angular material accordion example. Let’s add this component using the following commands.

ng g component ng-material/list
ng g component ng-material/nextPanel

To use the Angular material accordion, we need to import MatExpansionModule into our custom module. It is up to you to add all material modules in a separate custom module or root module app. We are adding all material modules in a custom module, it containing only the material module.

Open src/app/ng-material/ng-material.module.ts and replace the existing code with the code shown below we need the following material component for our example.

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { MatExpansionModule } from '@angular/material/expansion';
import { MatButtonModule } from '@angular/material/button';
import { MatInputModule } from '@angular/material/input';
import { MatIconModule } from '@angular/material/icon';
import { MatDatepickerModule } from '@angular/material/datepicker';
import { MatGridListModule } from '@angular/material/grid-list'
import { MatNativeDateModule } from '@angular/material/core';
import { CdkAccordionModule } from '@angular/cdk/accordion';
import { ListComponent } from './list/list.component';
import { NextPanelComponent } from './next-panel/next-panel.component';

@NgModule({
  declarations: [
    ListComponent,
    NextPanelComponent
  ],
  imports: [
    CommonModule,
    MatExpansionModule,
    MatButtonModule,
    MatIconModule,
    MatInputModule,
    MatDatepickerModule,
    MatNativeDateModule,
    MatGridListModule,
    CdkAccordionModule
  ],
  exports: [
    MatExpansionModule,
    MatButtonModule,
    MatIconModule,
    MatInputModule,
    MatDatepickerModule,
    MatNativeDateModule,
    MatGridListModule,
    CdkAccordionModule,

    ListComponent,
    NextPanelComponent
  ]
})
export class NgMaterialModule { }

We are importing all the required modules in our custom material module file and keeping separate modules for Angular material will make the application easy to maintain. Now we need to import our material module in the src/app/app.module.ts file.

...
import { NgMaterialModule } from './ng-material/ng-material.module';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
   ...
    NgMaterialModule,
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

To demonstrate the material list we need dummy data, create folder data in the assets and countries.json file and add the following dummy data.

[
    {
        "name": "France",
        "flag": "c/c3/Flag_of_France.svg",
        "area": 640679,
        "population": 64979548,
        "description": "France, the largest country in Western Europe, has long been a gateway between the continent's northern and southern regions."
    },
    {
        "name": "India",
        "flag": "4/41/Flag_of_India.svg",
        "area": 3287263,
        "population": 1324171354,
        "description": "India (Hindi: Bhārat), officially the Republic of India (Hindi: Bhārat Gaṇarājya) is a country in South Asia."
    },
    {
        "name": "Germany",
        "flag": "b/ba/Flag_of_Germany.svg",
        "area": 357114,
        "population": 82114224,
        "description": "Germany is a country located in the heart of Western Europe."
    }
]

We also need a model for our country to make strict types in our angular project. Create folder model and country.model.ts file and add the following code.

export interface ICountry {
    name: string;
    flag: string;
    area: number;
    population: number;
    description: string;
}

Step 2: An Example of Angular Material Accordion example

We have completed the material configuration, let us demonstrate our first example that uses most of the components and directives needed for creating an Angular material expansion panel. Here is a screenshot of our first example.

Angular material expansion panel example
Angular material accordion example

In the above image, we have used two mat-expansion-panel components, let’s edit the app.component.html template to add our Angular material expansion panel.

  <mat-accordion>
    <mat-expansion-panel>
      <mat-expansion-panel-header>
        <mat-panel-title>
          Accordion first item title
        </mat-panel-title>
        <mat-panel-description>
          Accordion summary without toggle icon
        </mat-panel-description>
      </mat-expansion-panel-header>

      <p> <b>This is the first item's accordion body.</b>
        An Angular material is an amazing UI for Angular framework, it
        has lots of pre-built components like card, modal, more, and Angular 
        material tabs are one of them.
      </p>
    </mat-expansion-panel>

    <mat-expansion-panel (opened)="secondPanelOpenState = true" 
      (closed)="secondPanelOpenState = false">
      <mat-expansion-panel-header>
        <mat-panel-title>
          Accordion second item title
        </mat-panel-title>
        <mat-panel-description>
          Expansion panel currently state : 
          {{ secondPanelOpenState ? 'open' : 'closed' }}
        </mat-panel-description>
      </mat-expansion-panel-header>
      <p> <b>This is the first item's accordion body.</b>
        Second item expansion is open
      </p>
    </mat-expansion-panel>
  </mat-accordion>

In our app component typescript, we need to add a secondPanelState property value to initialize false.

  secondPanelOpenState: boolean = false;

Angular Material accordion component, sub-components, and directives

Here we have listed components and directives used in the Angular material expansion panel.

NameDescription
mat-accordionThe mat-accordion is a root container containing a list of expansion panels.
mat-expansion-panelIn accordion, we have a list of expansion panels as items. Each expansion panel can contain a header and expandable panel.
mat-expansion-panel-headerIts header component of mat-expansion-panel, on clicking on it will expand its detail panel.
mat-panel-titleIt titles the section of each expansion panel and is a sub-component of the panel header.
mat-panel-descriptionIt is a child component of the expansion panel header, we can add an abstract or summary containing our panel.
mat-action-rowIt is a container where we can add a list of buttons or a button.
hideToggleIt is a directive we can add on the mat-expansion-panel to hide icons up and down on the header section.
[expanded]If we set this attribute value to true, mat-expansion-panel is set to open, by default is value is false.
Angular material accordain component and directive

Angular Material Accordion open by default

We have learned that we can use hideToggle attribute to make the Angular material accordion open by default. Let’s edit our first example template to add hideToogle attribute.

<div class="container">
  <mat-accordion>
    <mat-expansion-panel hideToggle [expanded]="true">
      <mat-expansion-panel-header>
      ....
      </mat-expansion-panel-header>
      ...
    </mat-expansion-panel>

    <mat-expansion-panel>
      <mat-expansion-panel-header>
        <mat-panel-title>
          Accordion second item title
        </mat-panel-title>
        .....
    </mat-expansion-panel>
  </mat-accordion>

Angular Material Expansion panel example 2

In our second example, we’ll add an image on the material expansion panel item. We are using the countries array object to iterate through each country using the *ngFor loop directive. Here is a screenshot of our second example.

Angular material expansion panel example
Angular material panel

In this example, we’ll also demonstrate how to add buttons inside the mat-action-row. Now let’s edit the list.component.ts file to retrieve our dummy countries using fetch API.

import { Component, OnInit } from '@angular/core';
import { ICountry } from 'src/app/models/country.model';

@Component({
  selector: 'app-list',
  templateUrl: './list.component.html',
  styleUrls: ['./list.component.scss']
})
export class ListComponent implements OnInit {
  countries: ICountry[] = [];
  constructor() { }

  ngOnInit(): void {
    fetch('./assets/data/countries.json').then(res => res.json())
      .then(json => {
        this.countries = json;
      });
  }
}

Once we have the country’s object, we can iterate through countries’ array objects inside our angular material expansion panel component and edit the list.component.html template file.

<mat-accordion>
    <mat-expansion-panel *ngFor="let country of countries; let i = index;">
        <mat-expansion-panel-header>
            <mat-panel-title>
                {{ country.name }}
            </mat-panel-title>
            <mat-panel-description>
                  {{ country.description }}
            </mat-panel-description>
        </mat-expansion-panel-header>
        <div class="content">
            <img [src]="'https://upload.wikimedia.org/wikipedia/commons/' + 
            country.flag" height="100" width="100" alt="country flag">
            <div class="content-text">
                <b>Population: </b>{{ country.population }}
                <b>Area : </b>{{ country.area }}
            </div>
             <mat-action-row>
                <button mat-stroked-button color="accent">Edit</button>
                <button mat-stroked-button color="accent"> Delete</button>
            </mat-action-row>
        </div>
    </mat-expansion-panel>
</mat-accordion>

How to add background color to active Angular Material Expansion panel header

In this example, we will demonstrate how to add background color to the Angular material panel header over the hover effect and background color to activate or expand the panel header. We will use the same countries array, here we have done the following step to add Angular material expansion panel header background color.

  1. Add selectedIndex as property variable, initial set to undefine and it can contain a current active index of Angular material panel.
  2. We have used the expansionPanelIndex method to set selectedIndex of the active index panel.
  3. Used ngStyle to add a condition by comparing the index with selectedIndex to add background color only to the activated panel.

Let’s edit the list.component.ts file to add code for the first and second steps.

import { Component, OnInit } from '@angular/core';
import { ICountry } from 'src/app/models/country.model';

@Component({
  selector: 'app-list',
  templateUrl: './list.component.html',
  styleUrls: ['./list.component.scss']
})
export class ListComponent implements OnInit {
  selectedIndex: number | undefined;   // Step 1
  countries: ICountry[] = [];

  constructor() { }

  ngOnInit(): void {
    fetch('./assets/data/countries.json').then(res => res.json())
      .then(json => {
        this.countries = json;
      });
  }

  expansionPanelIndex(index: number) { // Step 2
    this.selectedIndex = index;
  }

}

In the list.component.html template let’s add the ngStyle directive to compare the index with selectedIndex to add background color only to activate the Angular expansion panel header.

<mat-accordion>
    <mat-expansion-panel *ngFor="let country of countries; let i = index;">
        <mat-expansion-panel-header (click)="expansionPanelIndex(i)" 
           [style.background]="selectedIndex == i ? '#f79804' : '#ffffff'">
             
           // Same code as countries list
        </mat-expansion-panel-header>
        <div class="content">
           // Same code as countries list
        </div>

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

To add background color to Angular material expansion panel header when hover effect. Then we need to add the following CSS style to our component scss file.

mat-expansion-panel-header:hover {
    background: rgb(68, 137, 13) !important;
}

Creating Angular Material Accordion using cdk-accordion

In all our previous examples, we used the Angular material expansion panel component, Angular material also provides us with to create an Angular material accordion using the cdk-accordion component.

To use this component we need to import CdkAccordionModule, we already import this module in our custom material module. Here is a screenshot of our Angular accordion example using the CDK accordion module.

Angular accordion using CDK module
Angular material expansion panel

We have used the same countries array variable, let’s edit our component template.

  <cdk-accordion class="accordion">
    <cdk-accordion-item *ngFor="let country of countries; let index = index;" #accordionItem="cdkAccordionItem"
      class="accordion-item">
      <div class="accordion-item-header" (click)="accordionItem.toggle()">
        {{ country.name }}
        <span class="accordion-item-description">
          Click to {{ accordionItem.expanded ? 'close' : 'open' }}
        </span>
      </div>
      <div class="accordion-item-body" [style.display]="accordionItem.expanded ? '' : 'none'">
      {{ country.description }}
      </div>
    </cdk-accordion-item>
  </cdk-accordion>

To apply CSS style for our CDK accordion, let’s add the following CSS style in the component scss file.

.accordion {
    display: block;
    max-width: 800px;
  }
  
  .accordion-item {
    display: block;
    border: solid 1px rgb(150, 147, 147);
  }
  
  .accordion-item + .accordion-item {
    border-top: none;
  }
  
  .accordion-item-header {
    display: flex;
    align-content: center;
    justify-content: space-between;
  }
  
  .accordion-item-description {
    font-size: 0.85em;
    color: #202cd6;
  }
  
  .accordion-item-header,
  .accordion-item-body {
    padding: 10px;
  }
  
  .accordion-item-header:hover {
    cursor: pointer;
    background-color: rgb(143, 221, 78);
  }
  
  .accordion-item:first-child {
    border-radius: 4px 4px 0 0;
  }
  .accordion-item:last-child  {
    border-radius: 0 0 4px 4px;
  }

The mat-expansion-panel opens all by default & multiple expansions open

In this example, we want to open all material expansions by default and want to open multiple expansions when we click on the individual mat-expansion panel. Clicking on one of the new mat-expansion will default to close the open material expansion panel. Here is a screenshot of our example.

The mat-expansion-panel open all by default
The mat-expansion-panel opens all by default & multiple expansions open

In the component, typescript adds a list of posts, as follows.

posts = [
    { title:'First Post', content: 'First post content here.'},
    { title:'Second Post', content: 'Second post content here.'},
    { title:'Third Post', content: 'Third post content here.'}
];

Add multip=”true” to make multiple open of the material expansion.

<mat-accordion multi="true">
  <mat-expansion-panel [expanded]="true" *ngFor="let post of posts">
    <mat-expansion-panel-header>
        {{ post.title }}
    </mat-expansion-panel-header>
    <mat-panel-description>
        {{ post.content }}
    </mat-panel-description>
 </mat-expansion-panel>
</mat-accordion>

Conclusion
We have completed our Angular material accordion. This material component is useful for showing a list of vertically expandable related items. I hope you got some idea of how to use the Angular material dialog component.  If so then please share it with others and on social networks, this will encourage me to add more content. Follow me on my GitHub collection, I had code on Angular, react, and Ionic framework.

Check articles on the best and latest 2022, and 2021 Angular books to read for your journey from beginner to advanced level. BEST BOOK ON ANGULAR 2022 – 2021

Related Articles

How to implement Angular Material Accordion in Angular 13|14 .?

Leave a Reply

Your email address will not be published. Required fields are marked *

Scroll to top