
Posted on Jun 21, 2024
Building a Dashboard Layout Using CSS Grid
4 mins of reading
Businesses love dashboards. You’d be hard-pressed to find a UI engineer who has never worked on building or maintaining a dashboard UI. That is because dashboards embody a desirable promise: presenting valuable insights at a quick glance. Business intelligence (BI) metrics, system status charts, performance tracking over time, and financial metrics are some of the many common use cases that make this kind of user interface so ubiquitous in the business world.
The Problem
Yet, implementing a dashboard layout is seemingly still cumbersome. If you look at some of the leading dashboard libraries out there, they invariably use CSS Flexbox layout and a bunch of javascript logic to produce their layouts. That is more code to ship and maintain, more processing cycles on the client side, more work to support mobile devices, and often a jankier rendering experience.
The Solution
While those libraries have a lot of benefits beyond a widget layout, when you want something simple that is focused on layout, because you need a lot of control over the content of your dashboard’s widgets, there is a great solution built into every modern browser: CSS Grid layout.
Some of the advantages of using CSS Grid are:
- Not shipping any extra code.
- Virtually instantaneous rendering (layout-wise).
- Amazing flexibility in terms of sizing and positioning.
- Pixel-perfect alignment.
- Easily adaptable to different screen sizes.
- No need to learn a new library.
- And complete control of the design and content of each widget.
Trade-Offs
What are some of the disadvantages of this approach to building a dashboard?
- No “free” features. Yes, you don’t need to learn a new library and its paradigms and APIs, but you also don’t gain any of the features and pre-built UIs.
- Layout cannot be animated. Your widgets cannot be animated inside of a CSS Grid — for instance, if a user configures it to have a different size, or moves it around.
- Support is out of your control. While you don’t have to ship code for this layout, you also can’t control where it’s available, and ensure that how this feature is implemented does not change unintentionally. Browser standards should help avoid any major issues, though.
Implementation
Let’s look at how to implement a great dashboard layout using CSS Grid!
Creating a Dynamic CSS Grid
The first step is to create the grid itself. We’ll use the CSS repeat()
function, with the auto-fill
property, and a minmax()
function to ensure that our grid’s columns both fill up the screen and adjust their width automatically.
1 2 3 4 5 6 |
.DashboardGrid { display: grid; gap: 16px; grid-auto-rows: 200px; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); } |
The repeat()
function can be used with a multitude of values. Yes, you can pass in an integer for the first parameter, but that only defines a fixed number of columns for a grid. Instead, by using auto-fill
and minmax()
we create a grid with an indefinite number of columns. In this case, we squeeze in as many 200px
columns as possible, but they’ll stretch evenly to take up the full width of the grid.
Here we also set a gap
to space out the the dashboard widgets, and we define the height of each grid square as 200px
using grid-auto-rows
, which allows us to avoid having to set a predefined number of rows — the more dynamic we make this layout, the better!
Getting Tricky
This is a great grid, BUT… it is prone to gaps if you start adding widgets that are wider and/or taller than 1 cell. Luckily, there’s a CSS Grid trick to help avoid gaps:
1 2 3 4 5 6 7 |
.DashboardGrid { display: grid; gap: 16px; grid-auto-rows: 200px; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); grid-auto-flow: dense; /* The Fix! */ } |
By adding grid-auto-flow: dense
, we tell the browser to move widgets out of sequence if need be, in order to try to fill natural gaps in the grid. That may not always be appropriate, but if you want your dashboard to adapt to many screen sizes and still look good, this is probably the way to go.
Creating the Widgets
The last step is creating the container for the dashboard widgets.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
.w1 { grid-column: span 1; } .w2 { grid-column: span 2; } .w3 { grid-column: span 3; } .w4 { grid-column: span 4; } .h1 { grid-row: span 1; } .h2 { grid-row: span 2; } .h3 { grid-row: span 3; } .h4 { grid-row: span 4; } |
For a dashboard, you don’t need a wide range of widget widths and heights, especially with a grid with large cells. This gives us a range of rectangular sizes from 1 x 1 to 4 x 4, and everything in between.
Getting Responsive
But the final step is making these widgets adjust to different screen sizes. We do that by reducing widget sizes progressively, the smaller the screen size gets. With 200px
cells, we don’t need to even reduce wider widgets to a single cell, but you can tweak the resizing strategy to your needs — remember, using a CSS Grid here gives us a lot of flexibility.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
@media only screen and (max-width: 1399.998px) { .w4 { grid-column: span 3; } .h4 { grid-row: span 3; } } @media only screen and (max-width: 1099.998px) { .w3 { grid-column: span 2; } .w4 { grid-column: span 2; } .h3 { grid-row: span 2; } .h4 { grid-row: span 2; } } @media only screen and (max-width: 599.998px) { .w2 { grid-column: span 1; } .w3 { grid-column: span 1; } .w4 { grid-column: span 1; } } |
Putting It All Together
That’s a really nice looking, fast rendering dashboard layout!
Next Steps
You could easily implement this in a framework like React, where a Widget
component could accept width
and height
props and be rendered with the styles above. From there… it’s up to you, but that’s the beauty of this approach: you have full control over look and feel, and this will get you up and running quickly.
If you want to see and play around with some code, here’s a code pen with a pure HTML + CSS implementation based on the code samples in this article.