DEV Community

Cover image for expandable card in angular material using button.
ramtinmovahed
ramtinmovahed

Posted on

expandable card in angular material using button.

In this post, I'm going to implement a simple version of the expandable card with an action button in angular using angular material.
real deal
material design

Step 1: base initializations

create a new angular project by running

ng new my-app

we just need the basic functionalities for this demo, so we don't need routing and strict mode.

Then, install angular material by running:

ng add @angular/material

don't forget to enable the browser animations

next, delete the content of app.component.html

Step 2: Import the necessary modules

Based on material design, to implement, we need three components: card, divider, and button.

so in app.module.ts add them to the imports array

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppComponent } from './app.component';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { MatCardModule } from '@angular/material/card';
import { MatButtonModule } from '@angular/material/button';
import { MatDividerModule } from '@angular/material/divider';

@NgModule({
  declarations: [
    AppComponent,

  ],
  imports: [
    BrowserModule,
    BrowserAnimationsModule,
    MatCardModule,
    MatButtonModule,
    MatDividerModule,
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }
Enter fullscreen mode Exit fullscreen mode

Step 3: change the template

edit the app.component.html

<mat-card class="card">
  <mat-card-header>
    <mat-card-title>Title</mat-card-title>
    <mat-card-subtitle>Subtitle</mat-card-subtitle>
  </mat-card-header>
  <mat-card-content>
    <p>
      Lorem ipsum, dolor sit amet consectetur adipisicing elit. Exercitationem, praesentium sit tempora numquam vel odit
      dolorem qui quod sint distinctio! Quasi exercitationem tempore voluptas quam voluptatibus distinctio ex magni
      repellendus?
    </p>

    <p [@bodyExpansion]="state" class="expandable-content">
      [expandable] Lorem ipsum, dolor sit amet consectetur adipisicing elit. Exercitationem, praesentium sit tempora
      numquam vel odit
      dolorem qui quod sint distinctio! Quasi exercitationem tempore voluptas quam voluptatibus distinctio ex magni
      repellendus?
    </p>
  <mat-divider>
  </mat-divider>
  </mat-card-content>

  <mat-card-actions>
    <button mat-button (click)="toggle()" color="primary">EXPAND</button>
  </mat-card-actions>

</mat-card>
Enter fullscreen mode Exit fullscreen mode

the bodyExpansion is the name of the animation that we're going to implement next.
We needed to add the mat-divider component as specified in the material design spec.
The state is the name of the property that's responsible for the state of the animations

the toggle method will change this state (as you guest)

Step 4: adding the animations and implementing toggle method

change the content of app.component.ts

import { trigger, state, style, transition, animate } from '@angular/animations';
import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
  animations: [
    trigger('bodyExpansion', [
      state('collapsed, void', style({ height: '0px', visibility: 'hidden' })),
      state('expanded', style({ height: '*', visibility: 'visible' })),
      transition('expanded <=> collapsed, void => collapsed',
        animate('225ms cubic-bezier(0.4, 0.0, 0.2, 1)')),
    ])
  ]
})
export class AppComponent {
  title = 'my-app';

  state = 'collapsed';

  toggle(): void {
    this.state = this.state === 'collapsed' ? 'expanded' : 'collapsed';
  }
}
Enter fullscreen mode Exit fullscreen mode

In the animations array, we defined our animation. The trigger name is bodyExpansion that should match the trigger name that we set in the template. It has two states, collapsed and expanded. The collapsed state defines how the component should look when it's not expanded. So the height is zero and it's hidden.
The expanded state defines how it should look when it's expanded. So the height would be the actual height and it should be visible.
The transition defines how to move between these two states. the void=>collapsed is there to ensure it's collapsed when the component first renders.

The toggle method will change the state property that we defined above.

Final step: add the appropriate styles

In the app.component.css , add the following code

.card {
  width: 500px;
  margin: 50px auto auto auto;
}

.expandable-content {
  overflow: hidden;
}
Enter fullscreen mode Exit fullscreen mode

The thing to note here is the expandable-content class. This class makes the final fixes to the smooth transition.

Hope this was useful, have a nice day!

Top comments (2)

Collapse
 
muzafarali profile image
Ali • Edited

useful article on expandable, I make and it's work with one card if we need to apply on multiple cards then it expands and collapses all card with one click.

I'm looking for dynamic expand/collapse with multiple cards

Collapse
 
ramtinmovahed profile image
ramtinmovahed

you should pass indexes to each card in the template and toggle them in a separate method in the typescript file.