DEV Community

Cover image for Building a simple calendar with Vanilla JS
EliHood
EliHood

Posted on • Edited on

Building a simple calendar with Vanilla JS

In todays post, we'll be building a simple calendar using just vanilla JS. I will be using typescript, and using tsc to build out the index.js.

note: I'll be focusing more on the engine / loop part specifically, which i find to be the most important when it comes to this calendar algorithm.

The basis of making a calendar, requires two things really.

Lets make some generic html markup.

HTML

 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta http-equiv="X-UA-Compatible" content="ie=edge" /> <title>Some Calendar</title> <link rel="stylesheet" href="style.css" /> </head> <body> <div class="container"> <div class="calendar-body"> <div id="header"> <h1 id="month-heading"></h1> <div> <button id="backButton">Back</button> <button id="nextButton">Next</button> </div> </div> <div id="weekdays"> <div>Sunday</div> <div>Monday</div> <div>Tuesday</div> <div>Wednesday</div> <div>Thursday</div> <div>Friday</div> <div>Saturday</div> </div> <div id="calendar"></div> </div> </div> <script src="dist/index.js"></script> </body> </html> 
Enter fullscreen mode Exit fullscreen mode

Some CSS

 body, html{ height:100%; width:100%; padding:0px; margin:0px; } #month-heading{ padding: 0.1em; font-size: 1.4em; box-sizing: border-box; } .container{ display: flex; justify-content: center; width: 770px; height: auto; margin: 0 auto; } #header{ padding:10px; display: flex; justify-content: space-between; } .day + #currentDay{ background-color: #e8f4fa; } .prev-day{ background-color: #FFFCFF !important; box-shadow: none !important; } #weekdays{ width: 100%; display: flex; border-top: 1px solid #000; border-bottom: 1px solid #000; } #weekdays div{ width: 100px; padding: 10px; } .calendar-body{ background-color: #eee; margin: auto; width: 800px; height: auto; position: relative; } #calendar{ width: 100%; margin: auto; display: flex; flex-wrap: wrap; } .day{ width: 100px; padding: 10px; height: 100px; box-sizing: border-box; margin: 5px; background-color: #fff; box-shadow: 0px 0px 3px #CBD4c2; display: flex; flex-direction: column; justify-content: space-between; } 
Enter fullscreen mode Exit fullscreen mode

So lets get into the JS part.

Getting the first day of the month

 // specify the weekdays const weekDays = [ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", ]; 
Enter fullscreen mode Exit fullscreen mode

Setting up the Date Api.

 function main(){ const dt = new Date(); const month = dt.getMonth(); // 10 const year = dt.getFullYear(); // 2023 // gets first day of month based on the above params const firstDayOfMonth = new Date(year, month, 1); // Wed Nov 01 2023 00:00:00 GMT-0400 (Eastern Daylight Time) // tolocaleString parse the above date in a readable format.  const dateString = firstDayOfMonth.toLocaleString("en-us", { weekday: "long", year: "numeric", month: "numeric", day: "numeric", }); // Wednesday, 11/1/2023 /** * we want to get the first weekday of the month, * so we have a string of Wednesday, 11/1/2023. * * We want just the Wednesday part... so were going to make this string into an array. * so we split the string into array elements for every comma "," and leading white space. * dateString.split(", ") which gives us the following: * * (2) ['Wednesday', '11/1/2023'] */ const getFirstDayMonth = dateString.split(", ")[0]; // Wednesday const days = weekDays.indexOf(getFirstDayMonth); // returns an index of 3 being that Wednesday is the 3rd array element.  } 
Enter fullscreen mode Exit fullscreen mode

So we have some of the basis for our calendar program.

Lets get into the looping aspect...

The Loop

 ...main function continued.. const daysInMonth = new Date(year, month + 1, 0).getDate(); // 30 /** * lets then add days plus the days in the month so * * 3 + 30 */ const daysAndMonthTotal = days + daysInMonth; // 33 /** * we could create an array to reference its length */ const daysArr = new Array(daysAndMonthTotal); // 33 const day = dt.getDate(); // 26 for (let i = 1; i <= daysArr.length; i++) { const square = document.createElement("div") as any; square.classList.add("day"); /** * here we are saying substract the index from the days. * * * e.g * * Days will always be 3 in this case, and will always increment. * * So * 1 - 3 = -2 * 2 - 3 = -1 * 3-3 = 0 * 4-3 = 1 // we start here * */ const addedDay = i - days; .... } 
Enter fullscreen mode Exit fullscreen mode

Image description

 ...continued const addedDay = i - days; // so we start when i is greater than 3.  if (i > days) { square.innerText = addedDay; // if addedDay is today, lets give it a special color. if (addedDay === day) { square.id = "currentDay"; } } } 
Enter fullscreen mode Exit fullscreen mode

The complete code so far with some javascript event listeners added and etc.

 let nav = 0; const getCalendar = document.getElementById("calendar") as any; const weekDays = [ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", ]; function nextButton() { document.getElementById("nextButton")?.addEventListener("click", () => { nav++; main(); }); } function backButton() { document.getElementById("backButton")?.addEventListener("click", () => { nav--; main(); }); } function main() { const dt = new Date(); if (nav !== 0) { dt.setMonth(new Date().getMonth() + nav); } const month = dt.getMonth(); const year = dt.getFullYear(); const firstDayOfMonth = new Date(year, month, 1); const dateString = firstDayOfMonth.toLocaleString("en-us", { weekday: "long", year: "numeric", month: "numeric", day: "numeric", }); const lastDayOfLastMonth = new Date(year, month, 0).getDate(); ( document.getElementById("month-heading") as any ).innerText = `${dt.toLocaleDateString("en-us", { month: "long" })} ${year}`; getCalendar.innerHTML = ""; /** * we want to get the first weekday of the month, * so we have a string of Wednesday, 11/1/2023. * * We want just the Wednesday part... so were going to make this string into an array. * so we split the string into array elements for every comma "," and leading white space. * dateString.split(", ") which gives us the following: * * (2) ['Wednesday', '11/1/2023'] */ const getFirstDayMonth = dateString.split(", ")[0]; // Wednesday const days = weekDays.indexOf(getFirstDayMonth); /** * Lets get the days in the current month by the following */ const daysInMonth = new Date(year, month + 1, 0).getDate(); // 30 /** * lets then add days plus the days in the a month so * * 3 + 30 */ const daysAndMonthTotal = days + daysInMonth; // 33 /** * we could create an array the reference its length */ const daysArr = new Array(daysAndMonthTotal); // 33 const day = dt.getDate(); // 26 /** * We use the for loop to iterate through the daysArr * * If I = 1, and 1 is less than 33, render us some squares.. essentially */ for (let i = 1; i <= daysArr.length; i++) { const square = document.createElement("div") as any; square.classList.add("day"); /** * here we are saying substract the index from the days. * * * e.g * * Days will always be 3 in this case, and I will always increment. * * So * 1 - 3 = -2 * 2 - 3 = -1 * 3-3 = 0 * 4-3 = 1 // we start here * */ const addedDay = i - days; /** * if the index is greater than the first day of the month add text for numbers * * else add padding squares */ if (i > days) { square.innerText = addedDay; if (addedDay === day && nav === 0) { square.id = "currentDay"; } } getCalendar?.appendChild(square); } } nextButton(); backButton(); main(); 
Enter fullscreen mode Exit fullscreen mode

Image description

Last thing, lets add the previous days of last month.

 if (i > days) { square.innerText = addedDay; if (addedDay === day && nav === 0) { square.id = "currentDay"; } } else { // enter the last few days of last month here square.innerText = lastDayOfLastMonth - days + i; square.classList.add("prev-day"); } 
Enter fullscreen mode Exit fullscreen mode

lastDayOfLastMonth is the 31st of October. But were just getting the number not the month.

So we do 31 - 3 + i(1) = 29,

And then 31 - 3 + i(2) = 30, etc.

Image description

Completed Code

 let nav = 0; const getCalendar = document.getElementById("calendar") as any; const weekDays = [ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", ]; function nextButton() { document.getElementById("nextButton")?.addEventListener("click", () => { nav++; main(); }); } function backButton() { document.getElementById("backButton")?.addEventListener("click", () => { nav--; main(); }); } function main() { const dt = new Date(); if (nav !== 0) { dt.setMonth(new Date().getMonth() + nav); } const month = dt.getMonth(); const year = dt.getFullYear(); const firstDayOfMonth = new Date(year, month, 1); const dateString = firstDayOfMonth.toLocaleString("en-us", { weekday: "long", year: "numeric", month: "numeric", day: "numeric", }); const lastDayOfLastMonth = new Date(year, month, 0).getDate(); ( document.getElementById("month-heading") as any ).innerText = `${dt.toLocaleDateString("en-us", { month: "long" })} ${year}`; getCalendar.innerHTML = ""; /** * we want to get the first weekday of the month, * so we have a string of Wednesday, 11/1/2023. * * We want just the Wednesday part... so were going to make this string into an array. * so we split the string into array elements for every comma "," and leading white space. * dateString.split(", ") which gives us the following: * * (2) ['Wednesday', '11/1/2023'] */ const getFirstDayMonth = dateString.split(", ")[0]; // Wednesday const days = weekDays.indexOf(getFirstDayMonth); /** * Lets get the days in the current month by the following */ const daysInMonth = new Date(year, month + 1, 0).getDate(); // 30 /** * lets then add days plus the days in the a month so * * 3 + 30 */ const daysAndMonthTotal = days + daysInMonth; // 33 /** * we could create an array the reference its length */ const daysArr = new Array(daysAndMonthTotal); // 33 const day = dt.getDate(); // 26 /** * We use the for loop to iterate through the daysArr * * If I = 1, and 1 is less than 33, render us some squares.. essentially */ for (let i = 1; i <= daysArr.length; i++) { const square = document.createElement("div") as any; square.classList.add("day"); /** * here we are saying substract the index from the days. * * * e.g * * Days will always be 3 in this case, and I will always increment. * * So * 1 - 3 = -2 * 2 - 3 = -1 * 3-3 = 0 * 4-3 = 1 // we start here * */ const addedDay = i - days; /** * if the index is greater than the first day of the month add text for numbers * * else add padding squares */ if (i > days) { square.innerText = addedDay; if (addedDay === day && nav === 0) { square.id = "currentDay"; } } else { // enter the last few days of last month here. square.innerText = lastDayOfLastMonth - days + i; square.classList.add("prev-day"); } getCalendar?.appendChild(square); } } nextButton(); backButton(); main(); 
Enter fullscreen mode Exit fullscreen mode

Demo

Image description

Conclusion

Hopefully this was helpful, cheers 🥳

Credits:

https://unsplash.com/photos/a-calendar-with-red-push-buttons-pinned-to-it-bwOAixLG0uc

https://youtu.be/m9OSBJaQTlM?si=WQQkJHeqD8yPmvQc (inspiration)

Top comments (0)