
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><htmllang="en"><head><metacharset="UTF-8"/><metaname="viewport"content="width=device-width, initial-scale=1.0"/><metahttp-equiv="X-UA-Compatible"content="ie=edge"/><title>Some Calendar</title><linkrel="stylesheet"href="style.css"/></head><body><divclass="container"><divclass="calendar-body"><divid="header"><h1id="month-heading"></h1><div><buttonid="backButton">Back</button><buttonid="nextButton">Next</button></div></div><divid="weekdays"><div>Sunday</div><div>Monday</div><div>Tuesday</div><div>Wednesday</div><div>Thursday</div><div>Friday</div><div>Saturday</div></div><divid="calendar"></div></div></div><scriptsrc="dist/index.js"></script></body></html>
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:0auto;}#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:1pxsolid#000;border-bottom:1pxsolid#000;}#weekdaysdiv{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:0px0px3px#CBD4c2;display:flex;flex-direction:column;justify-content:space-between;}
So lets get into the JS part.
Getting the first day of the month
// specify the weekdaysconstweekDays=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday",];
Setting up the Date Api.
functionmain(){constdt=newDate();constmonth=dt.getMonth();// 10constyear=dt.getFullYear();// 2023// gets first day of month based on the above paramsconstfirstDayOfMonth=newDate(year,month,1);// Wed Nov 01 2023 00:00:00 GMT-0400 (Eastern Daylight Time)// tolocaleString parse the above date in a readable format.constdateString=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'] */constgetFirstDayMonth=dateString.split(",")[0];// Wednesdayconstdays=weekDays.indexOf(getFirstDayMonth);// returns an index of 3 being that Wednesday is the 3rd array element.}
So we have some of the basis for our calendar program.
Lets get into the looping aspect...
The Loop
...mainfunctioncontinued..constdaysInMonth=newDate(year,month+1,0).getDate();// 30/** * lets then add days plus the days in the month so * * 3 + 30 */constdaysAndMonthTotal=days+daysInMonth;// 33/** * we could create an array to reference its length */constdaysArr=newArray(daysAndMonthTotal);// 33constday=dt.getDate();// 26for(leti=1;i<=daysArr.length;i++){constsquare=document.createElement("div")asany;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 * */constaddedDay=i-days;....}
...continuedconstaddedDay=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";}}}
The complete code so far with some javascript event listeners added and etc.
letnav=0;constgetCalendar=document.getElementById("calendar")asany;constweekDays=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday",];functionnextButton(){document.getElementById("nextButton")?.addEventListener("click",()=>{nav++;main();});}functionbackButton(){document.getElementById("backButton")?.addEventListener("click",()=>{nav--;main();});}functionmain(){constdt=newDate();if(nav!==0){dt.setMonth(newDate().getMonth()+nav);}constmonth=dt.getMonth();constyear=dt.getFullYear();constfirstDayOfMonth=newDate(year,month,1);constdateString=firstDayOfMonth.toLocaleString("en-us",{weekday:"long",year:"numeric",month:"numeric",day:"numeric",});constlastDayOfLastMonth=newDate(year,month,0).getDate();(document.getElementById("month-heading")asany).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'] */constgetFirstDayMonth=dateString.split(",")[0];// Wednesdayconstdays=weekDays.indexOf(getFirstDayMonth);/** * Lets get the days in the current month by the following */constdaysInMonth=newDate(year,month+1,0).getDate();// 30/** * lets then add days plus the days in the a month so * * 3 + 30 */constdaysAndMonthTotal=days+daysInMonth;// 33/** * we could create an array the reference its length */constdaysArr=newArray(daysAndMonthTotal);// 33constday=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(leti=1;i<=daysArr.length;i++){constsquare=document.createElement("div")asany;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 * */constaddedDay=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();
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 heresquare.innerText=lastDayOfLastMonth-days+i;square.classList.add("prev-day");}
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.
Completed Code
letnav=0;constgetCalendar=document.getElementById("calendar")asany;constweekDays=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday",];functionnextButton(){document.getElementById("nextButton")?.addEventListener("click",()=>{nav++;main();});}functionbackButton(){document.getElementById("backButton")?.addEventListener("click",()=>{nav--;main();});}functionmain(){constdt=newDate();if(nav!==0){dt.setMonth(newDate().getMonth()+nav);}constmonth=dt.getMonth();constyear=dt.getFullYear();constfirstDayOfMonth=newDate(year,month,1);constdateString=firstDayOfMonth.toLocaleString("en-us",{weekday:"long",year:"numeric",month:"numeric",day:"numeric",});constlastDayOfLastMonth=newDate(year,month,0).getDate();(document.getElementById("month-heading")asany).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'] */constgetFirstDayMonth=dateString.split(",")[0];// Wednesdayconstdays=weekDays.indexOf(getFirstDayMonth);/** * Lets get the days in the current month by the following */constdaysInMonth=newDate(year,month+1,0).getDate();// 30/** * lets then add days plus the days in the a month so * * 3 + 30 */constdaysAndMonthTotal=days+daysInMonth;// 33/** * we could create an array the reference its length */constdaysArr=newArray(daysAndMonthTotal);// 33constday=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(leti=1;i<=daysArr.length;i++){constsquare=document.createElement("div")asany;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 * */constaddedDay=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();
Demo
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)
For further actions, you may consider blocking this person and/orreporting abuse