DEV Community

Michael De Abreu
Michael De Abreu

Posted on

Creating a Sidenav menu with Bootstrap

So far I've write mostly about Angular and Typescript, and that won't change. But today, I'll bring to you one quickly post about how to do a simple but effective Sidenav in Bootstrap.

GitHub logo michaeljota / bootstrap-examples

A couple of examples of components based on Bootstrap 4

Bootstrap Examples

This is a little repo just to show case some of the components I've made using Bootstrap. For each element there is a separate branch.

However notice that I'll using only Bootstrap. jQuery and Pooper.JS are also included, but just because they are required by Bootstrap.

How to use

You'll need node for this. Whatever version Parcel support.

  • npm install
  • Switch to whichever branch you want to check
  • npm start

As I'm using the same dependencies for all the examples, you don't need to reinstall when switching branches.




In that repo you will find the sidenav branch with all the final code.

What is a Sidenav?

A Sidenav is a collapsible component to place side, often and in this case, navigation content. Bootstrap have a Navbar Menu component that serves for some kind the same purpose, group navigational components, show them by default in a the Navbar, hide them in mobile, and toggle them when interacting with the manu button.

By default, Bootstrap show that menu below the Navbar, pushing the content to make space. The Sidenav instead, overlap the content, sometimes with a backdrop, but not this time.

First steps

I'll asume you have a Bootstrap project setup. If you don't, fell free to use the one of the master branch of the repo to start.

I will use the same snipped code from Bootstrap. You can read the documentation of the Navbar component, and copy the started snipped from here

You should have a page with a Navbar shows all the navigation items by default if the screen is large, and collapse them otherwise. Also, you should be able to toggle the menu when it's collapsed.

For this example, I will first test it for a extra small screen, so replace the .navbar-expand-lg class in the nav element, with a .navbar-expand-sm. This will indicate Bootstrap, the navbar should be expanded by default for any screen larger than small.

So, open your DevTools, and set the device to something extra small, like an iPhone 5S. I created another file just to place the sidenav styles, but you can place the code wherever you want. Create a .sidenav class, and add it to the div element with the .navbar-collapse.

Creating the sidenav

We want to do something that overlaps the screens when gets showed, and we can leverage to navbar component have a position: relative by default. So we can use position: absolute to place it as we want.

.sidenav {
  position: absolute;
}
Enter fullscreen mode Exit fullscreen mode

You should see like something is moving, but you can't actually see what it is. To be able to see all the elements, you need to set the position. This is a matter of taste really, but I will just place the menu just bellow the navbar, and expand it to take all the screen available.

.sidenav {
  position: absolute;
  top: 100%;
  height: calc(100vh - 100%) !important;
  left: 0%;
  width: 100%;
}
Enter fullscreen mode Exit fullscreen mode

You should now see how menu appear and disappear. This is because Bootstrap applies a .show class, that when is not present in the element, the element have a display: none. But we can also use it for our intention, of showing the menu from left to right. The !important in the height is because Bootstrap modify the style attribute of the element with a custom height.

.sidenav {
  position: absolute;
  top: 100%;
  height: calc(100vh - 100%) !important;
  left: 0%;
  width: 100%;
}

.sidenav:not(.show) {
  left: -100%;
}
Enter fullscreen mode Exit fullscreen mode

It don't seem to have any effect. But, actually the element is moving, from left to right. We are just not seeing the animation. I'm still learning about animations, that's why for this simple case I'll use the transition property.

.sidenav {
  position: absolute;
  top: 100%;
  height: calc(100vh - 100%) !important;
  left: 0%;
  width: 100%;
  transition: left 0.35s;
}

.sidenav:not(.show) {
  left: -100%;
}
Enter fullscreen mode Exit fullscreen mode

Now you have it. A good looking Sidenav. It wasn't hard. I did added a couple or more things to make it look nicer, a padding, and a background color, the same from the parent.

.sidenav {
  position: absolute;
  top: 100%;
  height: calc(100vh - 100%) !important;
  left: 0%;
  width: 100%;
  transition: left 0.35s;
  padding: 2rem;
  background-color: inherit;
}

.sidenav:not(.show) {
  left: -100%;
}
Enter fullscreen mode Exit fullscreen mode

Now, set a bigger screen in the DevTools device list, like an iPad.

What? You broke my app.

Ok, first I didn't say anything about using a real app. Second,

Fixing the big screen

The best you can do is to design to little screens, and latter fix it for the bigger ones. But this really seems to be mees up. What Bootstrap does, and what we will do, is wrap that class inside a media query. You can do what I did first, and just use the same media query that you are using for the .navbar-expanded-{media query}.

@include media-breakpoint-down(sm) {
  .sidenav {
    position: absolute;
    top: 100%;
    height: calc(100vh - 100%) !important;
    width: 100%;
    left: 0%;
    transition: left 0.35s;
    padding: 2rem;
    background-color: inherit;
  }

  .sidenav:not(.show) {
    left: -100%;
  }
}
Enter fullscreen mode Exit fullscreen mode

This have one disadvantage, now to modify the breakpoint you'll to adjust the .navbar-expand-* class, and also the breakpoint in the function. The advantage is that you don't need Bootstrap source files, and if you are doing something quickly, then this maybe your best option.

Or, you can use the same function that Bootstrap use. Notice that this is a private function, and it's currently not being exported. However, we can use the classic technique of copy-paste.

.navbar-expand {
  @each $breakpoint in map-keys($grid-breakpoints) {
    $next: breakpoint-next($breakpoint, $grid-breakpoints);
    $infix: breakpoint-infix($next, $grid-breakpoints);

    &#{$infix} {
      @include media-breakpoint-down($breakpoint) {
        .sidenav {
          position: absolute;
          top: 100%;
          height: calc(100vh - 100%) !important;
          width: 100%;
          left: 0%;
          transition: left 0.35s;
          padding: 2rem;
          background-color: inherit;
        }

        .sidenav:not(.show) {
          left: -100%;
        }
      }
    }
  }
}

Enter fullscreen mode Exit fullscreen mode

This loop block can currently be found inside the _navbar.scss file, at line 140. What it does, is associate all the mediaqueries from .navbar-expand-* to the corresponding media query. With this you can use whatever media query you want, only updating that class.

That's all folks!

Thanks for reading, I hope you find it interesting. I don't plan to publish this as a npm package because I think this is very opinionated. For instance, this example is using the position: relative default value of .navbar component, so if you want to apply another position as fixed or sticky, then you would have to update all the positional properties. Perhaps you want to use the light theme in your .navbar, but in the .sidenav you would to use the dark one. Again, you would need to modify according to your needs. However, I think this is a really simple way to start this, and adjust latter as you move.

Top comments (0)