No Time Dad

A blog about web development written by a busy dad

Tailwind Grid Layout Sidenav Starter Page

I had previously written about building a flexbox sidenav starter page using tailwind, so I thought it would be fun to try and create a responsive version of the starter page using tailwind’s grid utility classes instead. CSS grid is a great way to define the structure of pages, and I was curious to see what tailwind’s approach to it would be.

Skip ahead to the final code here.

The interesting thing about css grid is that I can define custom values for the width and height of columns and rows. This is problematic for css utility libraries like tailwind because there isn’t a way to pass a custom value to my selector properties using vanilla css.

In vanilla css, I could define my row heights as follows:

.Grid__Container {
  display: grid;
  grid-template-rows: 120px 1fr;
}

The above would initialize a css grid with two rows. The first row would have a height of 120 pixels, and the second row would fill all of the remaining space. This would be an example of the classic top navbar and content layout.

The bad news is there isn’t a way to specify custom row heights in tailwind using their vanilla grid-template-rows or grid-template-columns utility classes. Their utility classes default to all rows and columns using fractal units. Looking at the grid-template-rows documentation, defining a 2 row grid layout using tailwind via their grid-rows-2 utility class results in the following css:

grid-template-rows: repeat(2, minmax(0, 1fr));

The good news is that using tailwind I can create custom values for grid-template-rows and grid-template-columns. This turned out to be much less painful than I expected. I simply had to update my tailwind.config.js file’s theme.extend section with the corresponding key.

Building the sidenav

For the sidenav itself, I wanted this version to be responsive. Or at the very leat, set the ground work for responsiveness. On small screens, there should be a top navbar shown and the sidenav should be hidden. One larger screens, the top navbar should be hidden and the sidenav should be shown.

I think tailwind’s md: breakpoint is a good place to toggle the sidenav and top navbar. In my opinion, most tablets have a large enough screen to easily let users navigate with a sidenav instead of a menu dropdown from the top.

The starter template will consist of a parent container div, a child div for the top navbar, a second child div for the sidenav, and a third child div for the page content. As mentioned above, the top navbar and sidenav divs will be toggled via Tailwind’s hidden and block utility classes. Below is the basic structure of the html.

<div>
  <div>Header</div>
  <div>Sidenav</div>
  <div>Content</div>
</div>

Since tailwindcss is mobile first, I’ll start with the mobile view and build out to larger screens from there. The first thing I need to do is update my tailwind.config.js to contain the custom values for gridTemplateRows and gridTemplateColumns.

// tailwind.config.js
...
theme: {
  extend: {
    gridTemplateRows: {
      'custom-sidenav-layout': 'auto 1fr',
    }
  },
},
...

The above value will create two rows. The first row will let the content determine it’s height, and the second row will fill all remaining space.

In addition to the custom config value, I’ll want the height of the parent container to take up all of the view height. In tailwind, this is done via the h-screen utility class, which is equivalent to height: 100vh; in css. I’ll also initialize the grid, as well as my custom gridTemplateRows value in tailwind.config.js shown above. Borders are added to each row for debugging purposes and will be removed later.

<div class="h-screen grid grid-rows-custom-sidenav-layout">
  <div class="border-2 border-red-500">Header</div>
  <div class="border-2 border-blue-500">Content</div>
</div>
Header
Content

Now I need to add in the breakpoints for larger screens, as well as the third div for the sidenav. The sidenav should consist of two columns. The first column will be for the sidenav and it’s width will be determined by the size of it’s contents. The second column will be the content, which should take up all of the remaining space on the page.

Again, I’ll need to add a custom override value for gridTemplateColumns in my tailwind.config.js to acheive this. Below is the final version of that file for this starter layout.

// tailwind.config.js
...
theme: {
  extend: {
    gridTemplateRows: {
      'custom-sidenav-layout': 'auto 1fr',
    },
    gridTemplateColumns: {
      'custom-sidenav-layout': 'auto 1fr',
    }
  },
},
...
<div class="h-screen grid grid-rows-custom-sidenav-layout md:grid-cols-custom-sidenav-layout md:grid-rows-1">
  <div class="md:hidden border-2 border-red-500">Header</div>
  <div class="hidden md:block border-2 border-red-500">Sidenav</div>
  <div class="border-2 border-blue-500">Content</div>
</div>
Sidenav
Content

Conclusion

It’s almost too simple. Which, I guess, is good and bad. I’ll obviously need to add more to this layout, but it works well and the css wasn’t overly complicated. Figuring out how to extend and customize tailwind’s utility classes was the harded part. In the end, I have a great tailwind responsive starter template to build on.

Final code & demo
<div class="h-screen grid grid-rows-custom-sidenav-layout md:grid-cols-custom-sidenav-layout md:grid-rows-1">
  <div class="md:hidden border-2 border-red-500">Header</div>
  <div class="hidden md:block border-2 border-red-500">Sidenav</div>
  <div class="border-2 border-blue-500">Content</div>
</div>

The full responsive demo can be viewed here. Try resizing the screen size to see the layout change.