expandable card in angular material using button.
Tags: angular, webdev, materialdesign
Published: 2020-11-29 22:57:43

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](https://media.giphy.com/media/lB088iIVTBgF9gIXky/giphy.gif)
[material design](https://material.io/components/cards#anatomy)

####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
```typescript
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 { }
```
####Step 3: change the template
edit the app.component.html
```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>
```

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
```typescript
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';
  }
}
```

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
```css
.card {
  width: 500px;
  margin: 50px auto auto auto;
}

.expandable-content {
  overflow: hidden;
}
```

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!