Overview
In this tutorial I will cover rendering a calendar onto a webpage with a few lines of JavaScript, some CSS and a few lines of HTML. The calendar will include dropdowns for the months and the years using only plain old JavaScript. The process will be as follows:
- Render the months onto a dropdown
- Render the years onto a dropdown
- Render the days for the currently selected month/year combination
- Redraw the calendar when the months/years are changed
Changing the months and/or year will redraw the calendar to match the correct days for that given month and year.
If you are a beginner with JavaScript, or just need more insight, I highly recommend Secrets of the JavaScript Ninja which you can purchase on Amazon here. It's a solid read and the book gives a very deep dive into the many subtle aspects of JavaScript for those that are new to the language.
The final rendered calendar will look like the following.
Demo
SUN
MON
TUE
WED
THUR
FRI
SAT
The HTML
The calendar is comprised of a parent div with 3 main components inside of it. The first 2 components being the dropdowns for the months and another for a given range of years.
And because the days of the week are not likely to change anytime soon, I went ahead and created the calendars day headers manually. When the page loads, the script will grab the current users month and year from the browser and will draw a calendar based on the current date/time.
The HTML
<div class="calendar" id="calendar">
<div class="calendar-btn month-btn" onclick="$('#months').toggle('fast')">
<span id="curMonth"></span>
<div id="months" class="months dropdown"></div>
</div>
<div class="calendar-btn year-btn" onclick="$('#years').toggle('fast')">
<span id="curYear"></span>
<div id="years" class="years dropdown"></div>
</div>
<div class="clear"></div>
<div class="calendar-dates">
<div class="days">
<div class="day label">SUN</div>
<div class="day label">MON</div>
<div class="day label">TUE</div>
<div class="day label">WED</div>
<div class="day label">THUR</div>
<div class="day label">FRI</div>
<div class="day label">SAT</div>
<div class="clear"></div>
</div>
<div id="calendarDays" class="days">
</div>
</div>
</div>
Creating the months
Lucky for us, there are only 12 months in the year and we can store them as a simple array of strings. This array will be used to create the dropdown in the div with the id of "months".
<script>
var months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
function drawCalendarMonths()
{
for(var i = 0; i < months.length; i++)
{
var doc = document.createElement("div");
doc.innerHTML = months[i];
doc.classList.add("dropdown-item");
doc.onclick = (function () {
var selectedMonth = i;
return function ()
{
month = selectedMonth;
document.getElementById("curMonth").innerHTML = months[month];
loadCalendarDays();
return month;
}
})();
document.getElementById("months").appendChild(doc);
}
}
</script>
Running that function, the result should be the following:
Make note of the loadCalendarDays() function being called when we select a new month. This function will redraw the calendar whenever a new month is selected to reflect the new month selection.
Creating the years
We can follow a similar process to render the years dropdown.
function loadYears()
{
// whichever date range makes the most sense
var startYear = 1900;
var endYear = 2022;
for(var i = startYear; i <= endYear; i++)
{
var doc = document.createElement("div");
doc.innerHTML = i;
doc.classList.add("dropdown-item");
doc.onclick = (function(){
var selectedYear = i;
return function(){
year = selectedYear;
document.getElementById("curYear").innerHTML = year;
loadCalendarDays();
return year;
}
})();
document.getElementById("years").appendChild(doc);
}
}
Note that I started the years dropdown at 1900 and ended it at 2022. You can of course update those variables to fit your own needs.
The process is essentially the same though as with rendering months. If any year is selected, the loadCalendarDays() function will be called in order to re-render the calendar days.
Creating the days
Now we're at the heart of the calendar. Day rendering is somewhat similar to the previous month and year generation functions. We're essentially going to calculate the number of days in a specified year/month period and then create a <div> for each one of the days calculated.
Also note that this function gets called whenever the calendar
requires redrawing, such as when we select a new month or a new year
from either of those dropdowns.
daysInMonth(): I created a helper function called daysInMonth() that will return the number of days in a month/year period selected. We'll essentially loop through these days and create a 'day' element onto our calendar for each one found.
getDay(): The JavaScript Date object provides us with the getDay() method which will return the day of the week for any given date. In our case, we want to know when the very first day of the month will lie on. And we'll ignore the previous days leaving up to that by creating empty 'day' elements with no particular meaning.
function daysInMonth(month, year)
{
let d = new Date(year, month+1, 0);
return d.getDate();
}
function loadCalendarDays()
{
document.getElementById("calendarDays").innerHTML = "";
var tmpDate = new Date(year, month, 0);
var num = daysInMonth(month, year);
var dayofweek = tmpDate.getDay(); // find where to start calendar day of week
Here I'm clearing the "canvas", as it were, and calculating the total days in the month and the day of the week where we will begin the month.
// create day prefixes
for(var i = 0; i <= dayofweek; i++)
{
var d = document.createElement("div");
d.classList.add("day");
d.classList.add("blank");
document.getElementById("calendarDays").appendChild(d);
}
We'll want to ignore any days leading up to the first day of the calendar. The above loop will essentially add empty day elements to the calendar. And the following function will render the actual calendar days onto the main div container.
// render the rest of the days
for(var i = 0; i < num; i++)
{
var tmp = i + 1;
var d = document.createElement("div");
d.id = "calendarday_" + i;
d.className = "day";
d.innerHTML = tmp;
document.getElementById("calendarDays").appendChild(d);
}
var clear = document.createElement("div");
clear.className = "clear";
document.getElementById("calendarDays").appendChild(clear);
}
In part 2
At this point, you should have a calendar to display that can render the days for any given month and year combination. In part 2, I'll go over single date selections, date range selections and custom events for each day. In the meantime, feel free to download the resource files down below and update, modify, improve, and enjoy the code.
Update: Part 2 can be found right over here.