Search code examples
cssangularangular-material

Angular Material - Mat-Accordion Shadow effect on selection of that Accordion Description Item


I am using Angular Material 14 with Angular 15 and below is the code to display Menu items with mat-nav-list

<mat-nav-list role="list">
    <a mat-list-item role="listitem" class="list-item-setting" matTooltipPosition="right" routerLinkActive="active"
    [routerLinkActiveOptions]="{exact:true}" class="admin-link">
    <mat-icon class="list-item-setting">user1</mat-icon>
    <span>User 1</span>
    </a>

    <a mat-list-item role="listitem" class="list-item-setting" matTooltipPosition="right" routerLinkActive="active"
    [routerLinkActiveOptions]="{exact:true}" class="admin-link">
    <mat-icon class="list-item-setting">user2</mat-icon>
    <span class="nowrap">User 2</span>
    </a>

    <a mat-list-item role="listitem" class="list-item-setting" matTooltipPosition="right" routerLinkActive="active"
    [routerLinkActiveOptions]="{exact:true}" class="admin-link">
    <mat-icon class="list-item-setting">user3</mat-icon>
    <span class="nowrap">User 3</span>
    </a>
    <mat-accordion>
    <mat-expansion-panel hideToggle [(expanded)]="panelOpenState" class="mat-elevation-z0">
      <mat-expansion-panel-header>
        <mat-panel-title style="text-align: left">
          <img src="../../../../assets/images/icon_bell.svg">
          <span class="add-padding-to-mat-panel-header"><a class="list-item-setting" routerLinkActive="active">Submenu
              Accordion</a></span>
        </mat-panel-title>
      </mat-expansion-panel-header>
      <div>
        <mat-panel-description mat-list-item role="listitem" id="notificationListId"
          class="mat-panel-description-setting"><a class="list-item-setting" routerLinkActive="active"
            [routerLinkActiveOptions]="{exact:true}">Submenu 1
          </a></mat-panel-description>
        <mat-panel-description mat-list-item role="listitem" id="subscriberGroupsId"
          class="mat-panel-description-setting"><a class="list-item-setting" routerLinkActive="active"
            [routerLinkActiveOptions]="{exact:true}" style="white-space: nowrap;">Submenu 2</a></mat-panel-description>
        <mat-panel-description mat-list-item role="listitem" id="allSubscribersId"
          class="mat-panel-description-setting"><a class="list-item-setting" routerLinkActive="active">Submenu
            3</a></mat-panel-description>
      </div>
    </mat-expansion-panel>
    </mat-accordion>
</mat-nav-list>

And below is the Menu list that appears with this code..

Shadow Band

The CSS Code related to the Menu is below...

.mat-panel-description-setting {
    color: $white;
    padding-top: 10px;
    padding-left: 30px;
    flex-basis: 100%;
}

.mat-expansion-panel-header {
    padding: 0 16px !important;
}
  
.list-item-setting {
    padding: 0!important;
    padding-left: 16px;
    color: $white;
}

.add-padding-to-mat-panel-header {
    color: $white;
    padding-left: 16px;
}

How can I make the same effect for the Submenu Accordion Description items on selection of any one of the Submenu items in the list. I mean to say, if user selects Submenu 2, then it should highlight with Band(Shadow effect) that I have shown in the picture for that Submenu 2 item.

I tried using <mat-nav-list></mat-nav-list> for the Accordion Submenu items and it is not accepting there..

EDIT

With the code given in the Answer, I am getting as below screenshot. I have changed your code little bit like - using @HostListener instead of document.addEventListener. The grey background is not going away on click of 2nd Submenu item. And the width is covering only to that text.

Submenu Accordion

Can anyone throw some light on this..


Solution

  • Posting a more "Angular" approach to this problem as the current solution offered, while it certainly solves the problem, it does leverage what I would consider to be Angular anti patterns.

    Leverage @ViewChildren to retrieve ElementRef from the DOM via the MatListItem class.

    @ViewChildren(MatListItem, { read: ElementRef }) listItems!: QueryList<ElementRef>;
    

    Import Renderer2 for styling of the elements.

    Using Renderer2 ensures vended compilations are compliant with regard to specified targets.

    constructor(private renderer: Renderer2) {}
    

    Function to hanleSelectionState.

    // Function to reset the background color of all elements
    public handleSelectionState(e: any) {
      // loop over all elements to remove any is-active attributes
      this.listItems.forEach((listItem) => {
        this.renderer.removeAttribute(listItem.nativeElement, 'is-active', '');
      });
      // use target on click event to set attribute is-active 
      this.renderer.setAttribute(e.currentTarget, 'is-active', '');
    }
    

    Add CSS to styles.scss for the is-active attribute

    [is-active] {
      background-color: lightgray;
    }
    

    In the HTML bind the click event to the hanleSelectionState function

    <mat-list-item (click)="handleSelectionState($event)">
      <mat-icon class="list-item-setting">email</mat-icon>
      <span class="add-padding">User 1</span>
    </mat-list-item>
    

    STACKBLITZ

    https://stackblitz.com/edit/stackblitz-starters-sidenav-xrwfts?file=src%2Fapp%2Flist-overview-example.ts