Adjusting Mat Expansion Indicator Rotation

After successfully moving the mat Indicator to the left and using the transform attribute to make it turn inward when expanding, I now want to style it so that the indicator faces upward when expanded and downward when collapsed. How can I achieve this unique styling? Visit this link for more information.

expansion-overview-example.css

  .mat-expansion-panel-header {
       flex-direction: row-reverse;
   } 

Global styles.css

  .mat-expansion-indicator::after {
      transform: rotate(225deg) !important;  
}

Answer №1

This unique animation controls the rotation of the mat expansion indicator. The animation, found here, simply uses a rotate(180deg) directive to rotate the indicator 180 degrees clockwise. Initially, the indicator is set to rotate(45deg), displaying a downward icon when the panel is closed and an upward icon when open with a clockwise animation.

If you try to adjust the rotation using:

.mat-expansion-indicator::after {
    transform: rotate(225deg) !important;  
}

The result is that the icon rotates upwards when the panel is closed. When clicked, it then rotates by 180 degrees clockwise. This configuration prevents showing a downward icon when closed and an upward one when opened due to the rotate(225deg) setting. Changing this sacrifices inward turning as the animation initiates clockwise instead of counterclockwise, which is what we need.

Unfortunately, Angular Material does not provide a built-in way to override default animations, as documented here.

To achieve the desired counterclockwise rotation, my solution involves completely disabling default animations on mat-expansion-panel-header and creating a custom directive to mimic the desired animation in a counterclockwise direction.

Firstly, disable the default animation on mat-expansion-panel-header:

<mat-expansion-panel-header [@.disabled]="true">

Create new animations in styles.css that match the timing and behavior of the default animation:

@keyframes inwards-open {
  0%   { transform: rotate(0deg); }
  100% { transform: rotate(-135deg); }
}

@keyframes inwards-close {
  0%   { transform: rotate(-135deg); }
  100% { transform: rotate(0deg); }
}

.openAnimate {
  animation: inwards-open 225ms cubic-bezier(0.4,0.0,0.2,1) !important;
}

.closeAnimate {
  animation: inwards-close 225ms cubic-bezier(0.4,0.0,0.2,1) !important;
}

Next, implement a custom directive that manages the animation status based on panel opening and closing events:

import { Directive, ElementRef, HostListener, AfterViewInit, OnDestroy } from '@angular/core';
import { fromEvent, Subscription } from 'rxjs';

@Directive({
  selector: '[appCustomMatExpansionToggle]'
})
export class CustomMatExpansionToggleDirective implements AfterViewInit, OnDestroy {
  private elem: HTMLSpanElement;
  private uns: Subscription;
  constructor(private elRef: ElementRef) {}

  ngAfterViewInit() {
    this.elem = this.elRef.nativeElement.querySelector(".mat-expansion-indicator");

    this.uns = fromEvent(this.elem, 'animationend').subscribe(() => {
      this.elem.classList.remove("openAnimate");
      this.elem.classList.remove("closeAnimate");
    });
  }

  @HostListener("opened")
  onOpen() {
    this.elem.classList.add("openAnimate");
  }

  @HostListener("closed")
  onClose() {
    this.elem.classList.add("closeAnimate");
  }

  ngOnDestroy() {
    this.uns.unsubscribe();
  }
}

Finally, apply the custom directive to mat-expansion-panel:

<mat-expansion-panel appCustomMatExpansionToggle>

For a demonstration, check out this working demo: https://stackblitz.com/edit/indicatorrotation-mp73uh

Answer №2

Turn off default animation:

<mat-expansion-panel-header [@.disabled]="true">

Modify styles in a global styles.scss file

  .mat-expansion-panel {
    .mat-expansion-indicator {
      transition: transform .3s ease;

      &::after {
        transform: rotate(-135deg);
      }
    }

    &.mat-expanded {
      .mat-expansion-indicator {
        transform: rotate(40deg) !important;
      }
    }
  }

Answer №3

Hey Ivan, just a quick tip - you can achieve the desired result with this code snippet without having to disable animations (I understand that ng-deep is no longer recommended):

:host ::ng-deep .mat-expansion-panel {
  .mat-expansion-indicator {

    &::after {
      transform: rotate(-135deg) !important;
    }
  }

  &.mat-expanded {
    .mat-expansion-indicator {
      transform: rotate(180deg) !important;
    }
  }
}

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

Guide on implementing autocomplete in Angular Material with a dynamic SQL data source

I struggled to get it working using the mat-table option and even searched on YouTube, only finding hard-coded autocomplete examples. I have included some relevant code segments - thank you for your assistance. Visit this link for more information on Angu ...

GWT Designer style issue plaguing development efforts

Currently, I am working on designing a login view using GWT Designer while incorporating styles from Twitter Bootstrap. The structure I have set up is as follows: However, the displayed result does not meet my expectations: Despite setting all CSS paddi ...

Learn the process of integrating app-ads.txt into an Angular localized project hosted on Firebase

I placed the app-ads.txt file in the src folder of my project. In the angular.json file, I included "src/app-ads.txt" in the "assets" section: "assets": [ .... "src/app-ads.txt" ], ... Next, ...

Mobile browser not resizing window width in fluid layout on WordPress site

Currently, I am working on developing a basic web layout that can adapt to mobile view. I have made some progress which you can check out here. The layout successfully adjusts when the window is resized in Firefox or Chrome. However, when I tried to acce ...

What is the best way to verify that the normalized CSS is functioning correctly in AngularJS?

How can I verify if the normalized css is functioning correctly in Angular.js after importing normalized.css into the style.css file? When I try to import by using Cntrl + click, it displays a "file not found" error message. The steps I followed to add no ...

Does the 'span' element negatively impact the vertical alignment of text?

While working on my code, I noticed an issue with vertical alignment when using span tags to change the background of the text based on its content. The problem occurs specifically when viewing the code in the Android Chrome browser. You can view the initi ...

Issue: Module "expose?Zone!zone.js" could not be located

Just started experimenting with Angular 2 and encountering an issue when importing zone.js as a global variable: https://i.stack.imgur.com/gUFGn.png List of my packages along with their versions: "dependencies": { "angular2": "2.0.0-beta.3", "es ...

Personalized styling in material-ui v4.9.0

I recently updated the Material UI version in my project from 0.20 to v4.9. I have successfully changed all the imports to @material-ui/core and my app is compiling without any issues. However, I am facing a problem with the styling. Previously, I did not ...

`Square payment integration using the mean stack technology stack`

Seeking advice on how to integrate Square payment form with angular and node. The form functions properly, but upon hitting send, it fails to post to /process-payment. As a newcomer to the MEAN stack, I am unsure where to start regarding using angular and ...

Guide on importing Lodash into your Angular project on Stackblitz

Encountering an issue with lodash debounce in my Angular project on Stackblitz. Despite installing lodash in the dependencies, I am receiving a 'lodash module not found' error. You can check out the error at this link: https://stackblitz.com/edit ...

Issue with fancyBox not functioning properly when integrated with a caption script

Hey there! I've been working with both jQuery's fancyBox for displaying image/video galleries and the Capty script for showing image titles on images. However, I've run into a snag - when the title is displayed on the image, fancyBox st ...

Customizing data input in ngx chart's bubble chart is essential for creating a unique

For my project, I utilized the ngx-chart bubble chart. However, I encountered an issue when the data was in the following format: multi: any[] = [{ "name": "Kuwait", "series": [{ "name": "a", "waiting time": 24, "real time": 38, "queue size": 31 }, { " ...

Navigating the challenges of time zones when calculating lag times

I am currently attempting to calculate the lag in milliseconds between my client (located in France) and my server (based in Germany). On the Client side (Using Angular Typescript) : this.http.getDate().subscribe(response => { if (respo ...

Upgrade from RxJS 4 to RxJS 6

How can I convert this Rxjs 4 code snippet to Rxjs 6? const click$ = Rx.Observable.fromEvent($('.btn'), 'click').share(); click$ .scan((a, b) => a + 1, 0) .bufferTime(4000, null, 3) .filter(buffer => buffer.length > 0) ...

Locate the closest point among a set of coordinates to a specified point

I have a situation where I have an object that contains latitude and longitude attributes. My goal is to find the closest match in an array of similar objects by considering both latitude and longitude. obj = {latitude: 55.87, longitude: 4.20} [ { & ...

Tips on ending loading animation once the screen has finished loading

@import url(http://fonts.googleapis.com/css?family=Play:400,700); * { box-sizing: border-box; } body { background-color: #222; font-family: "Play"; } h1 { font-size: 2rem; color: #FFF; text-align: center; text-transform: uppercase; } .smar ...

Tips for adjusting the <object> video to perfectly match the width and height of its parent container

<div id="player" width='2000px' height='600px'> <object id="pl" classid="CLSID:6BF52A52-394A-11d3-B153-00C04F79FAA6"> <param name='url' value='Video/3.mp4'/> <param name='ShowContro ...

Simplifying my question as "directing to another webpage" is an inadequate description

I am currently customizing my website using a template that includes an element called 'portfolio-filters.' This element is located on my blog page and can be seen in the following image: portfolio-filters When a visitor interacts with these bu ...

Issue with importing Control in Ionic 2 leads to errors

I am encountering an issue when trying to import Control for email Validator in my Ionic 2 RC0 project. Below is the code snippet: /** * Created by adirz on 10/14/2016. */ import { Control } from '@angular/common'; export class EmailValidator ...

Maintain the current layout, but reduce its size on mobile devices

For quite some time, I have been struggling to make my website mobile-friendly. Despite using a grid layout, the website looks terrible when viewed on phones. All I want is to scale down the desktop version to half the size when accessed on phones. I&apo ...