How to build a calendar with CSS Grid
Building a calendar with CSS Grid is actually quite easy. I want to show you how to do it.
Here’s what you’ll create by the end of this article:
Creating the HTML
You can tell from the image that the calendar contains three parts:
- The month indicator
- The weekday/weekend indicator
- The dates themselves
The best way to structure the HTML is to go with what feels right. We’ll create the HTML according to these three sections:
<div class="calendar">
<div class="month-indicator">...</div>
<div class="day-of-week">...</div>
<div class="date-grid">...</div>
</div>
You should also be able to see we need seven columns for the grid.
We’ll focus the conversation on .day-of-week
and .date-grid
since we’re only talking about grid.
Structuring the grid
There are two ways to create the CSS Grid.
The first way is to merge elements within .day-of-week
and .date-grid
into one selector. If we do this, we can set the selector in display: grid
. Here’s what the HTML would have looked like if we did this:
<div class="grid">
<!-- Day of week -->
<div>Su</div>
<div>Mo</div>
<div>Tu</div>
<div>We</div>
<div>Th</div>
<div>Fr</div>
<div>Sa</div>
<!-- Dates -->
<button><time datetime="2019-02-01">1</time></button>
<button><time datetime="2019-02-02">2</time></button>
<button><time datetime="2019-02-03">3</time></button>
<!-- ... -->
<button><time datetime="2019-02-28">28</time></button>
</div>
I discourage this method because the HTML loses its structural meaning. I prefer keeping .day-of-week
and .date-grid
as separate elements if possible. This makes it easy for me to read/understand the code I’ve written.
Here’s the HTML structure i chose to go with:
<div class="day-of-week">
<div>Su</div>
<div>Mo</div>
<div>Tu</div>
<div>We</div>
<div>Th</div>
<div>Fr</div>
<div>Sa</div>
</div>
<div class="date-grid">
<button><time datetime="2019-02-01">1</time></button>
<button><time datetime="2019-02-02">2</time></button>
<button><time datetime="2019-02-03">3</time></button>
<!-- ... -->
<button><time datetime="2019-02-28">28</time></button>
</div>
The best way to create a CSS Grid with the structure I proposed is to use subgrid. Unfortunately, most browsers don’t support subgrid yet. In the meantime, the best way is to create two separate grids—one for .day-of-week
and one for .date-grid
.
Both .day-of-week
and .date-grid
can use the same seven-column grid.
/* The grid */
.day-of-week,
.date-grid {
display: grid;
grid-template-columns: repeat(7, 1fr);
}
Pushing the dates
February 2019 begins on a Friday. If we want the calendar to be correct, we need to make sure:
- 1 Feb 2019 falls on Friday
- 2 Feb 2019 falls on Saturday
- 3 Feb 2019 falls on Sunday
- And so on…
With CSS Grid, this part is easy.
CSS Grid has placement algorithm that kinda follows the following rules (if you didn’t set grid-auto-flow
to dense
):
- Place items that have explicit
grid-column
orgrid-row
first - Fill in the rest according to the last-placed item
What this means is:
- If the first item falls on column 6
- The second item will be placed in column 7.
- The third item will be placed on the next row, in column 1 (because there are only seven columns).
- The fourth item will be placed in column 2,
- And so on…
So, if we position 1 February on the sixth column (friday), the rest of the dates will be placed correctly.
Simple as that!
/* Positioning the first day on a Friday */
.date-grid button:first-child {
grid-column: 6;
}
Here’s a codepen for you to play with:
See the Pen Building a Calendar with CSS Gridby Zell Liew (@zellwk) onCodePen.
Want to learn more?
This article contains one fraction of a component (a datepicker) from Learn JavaScript. There’s so much more I want to show you. (But they’re mostly JavaScript related topics).
For example, in Learn JavaScript, I show you how to:
- Build a calendar for any month (and any year)
- Add a previous/next button to switch between months
- Click on each date to display a date
Here’s what it looks like:
If you want to learn to build this datepicker, I highly recommend joining Learn JavaScript when enrolment opens in July 2019. I’m excited to share it with you!