angularangular-materialmat-sidenav

Any way to mix 'push' and 'over' modes of Angular Material mat-sidenav?


Please check the code here: https://stackblitz.com/edit/angular-sidenav-mixedpushover

I would like to set up an angular material sidenav so that it has a toggle button that is always visible and slides with the sidenav as it opens and closes. The main content area should be obscured by both the button and the sidenav when it is open (i.e. mode="over").

Basically I want the sidenav to operate in "over" mode but to "push" the button that toggles it.

I have tried several approaches but nothing works quite right. My current implementation (not shared because it's too hard to make a simple example of) has two toggle buttons: one that is positioned at the edge of the screen which is shown/hidden manually, and another button that is part of the sidenav content itself. If you squint, it almost behaves like a single button that slides with the sidenav! I also used some animations to try to blend the two buttons a bit, but it is very hard to match the speed of the sidenav.

Some pictures of what I am trying to do.

Sidenav is closed:

Sidenav is closed

Sidenav is open:

Sidenav is open

Does anybody have any workable suggestions? Thank you!


Solution

  • If you just want to see the result, go to the end of the answer

    The main thing to do is to disjoint the toggle button from the sidenav.

    HTML

    <p><button [ngClass]="{'button':true,'open':opened}" (click)="toggle()">Open</button></p>
    
    <mat-sidenav-container class="sidenav" (backdropClick)="close()">
      <mat-sidenav #sidenav (keydown.escape)="close()" disableClose position="end">
        <p>Sidenav content</p>
      </mat-sidenav>
    
      <mat-sidenav-content>
        Page content with "over" sidenav
      </mat-sidenav-content>
    </mat-sidenav-container>
    

    Here you got your button out of the sidenav, the classes allow you, first to place the button where you want - with button class - and then to move it when you open or close your sidenav - with open class.

    The (backdropClick)="close()" and the (keydown.escape)="close()" are here to be sure that we move the toggle button even if we don't close the sidenav with it.

    So the style for this is this

    CSS

    .button{
      position:absolute;
      width:40px;
      height:40px;
      background-color: green;
      color:black;
      border-top-left-radius:5px;
      border-bottom-left-radius:5px;
      top: 50%;
      right:0;
      z-index: 2;
      transform: translate3d(0,0,0);
      transition:0.4s cubic-bezier(0.25, 0.8, 0.25, 1);
    }
    
    .open{
      transform: translate3d(-200px,0,0);
      transition:0.4s cubic-bezier(0.25, 0.8, 0.25, 1);
    }
    

    On the transition effect, you see a cubic-bezier(0.25, 0.8, 0.25, 1); which is the transition used by the sidenav to display it's content. So with this transition used into our button, it will perfectly fit the sidenav moves.

    And finally on your typescript file, you just need the functions to toggle your sidenav

    TS

    @ViewChild('sidenav') sidenav: MatSidenav;
    
    opened: boolean = false;
    
    toggle(){
      this.opened = !this.opened
      if(this.opened){
          this.sidenav.open();
        }else{
          this.sidenav.close();
        }
    }
    
    close() {
      this.opened = false;
      this.sidenav.close();
    }
    

    Here you can see a working stackblitz.