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 open:
Does anybody have any workable suggestions? Thank you!
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.