Creating Calendar in JavaScript
Warning
A calendar in plain JavaScript, no libraries. This project is based on my internship at Woowa Bros, a unicorn food-delivery startup in Seoul, back in Woowa Tech Camp.
Show me the code first.
GitHub - anaclumos/calendar.js: Vanilla JS Calendar
Show me the demo first.
Goals
- Use functional programming* over object-oriented programming.
- No DOM manipulation after init. This philosophy is based on React (or any Single Page Application library). DOM manipulation can be highly confusing if 30 different codes try to edit the same thing, so we will rerender the components if we need to edit something.
💡 Don't fix it. Buy a new one.
That's rerendering in front-end, in one line.
Stack
- JavaScript
DateObject - CSS
display: gridwill be useful.
Basic Idea
- There will be a global
displayDateobject that represents the displaying month. navigator.jswill change thisdisplayDateobject, and triggerrenderCalendar()function withdisplayDateas an argument.renderCalendar()will rerender with the calendar.
Before anything, prettier!
Prettier helps write clean and neat code with automatic formatting.
Now throw in some HTML.
I generated this boilerplate with VS Code.
Then trick VS Code to read JS String as HTML Tags.
Vanilla JavaScript means no JSX-style highlighting. Our HTML will live in JavaScript strings, with no highlighting or Intellisense. So, a function that tricks VS Code into reading the string as HTML.
to be added - screenshot of highlighting
calendar.js
Then we connect calendar.js and index.html.
Defining constants will help before writing renderCalendar().
NUMBER_OF_DAYS_IN_WEEK kills the magic number. A random 7 in code can be tough to decipher. A constant like this increases maintainability.
If there was a random 7, who knows if we are iterating through the number of Harry Potter Books?
This code block will be the baseline for our calendar generation. We will pass in the HTML target and a day object. today is the month on screen and comes from navigator.js. Navigator gives the real date for this month and the first of the month for other months.
Now, we need four different Date objects for displaying the calendar. We could've used fewer, but that's up to the implementation. Cutting date objects here would buy a tiny bit of performance and make the code much harder to follow, so four objects feels like a fair middle ground.
Four Date objects we need
- The last day of last month: needed to highlight last month's weekend and display the correct date for last month's row.
- The first day of this month: needed to highlight this month's weekend and figure out how many days of last month we need to render.
- The last day of this month: needed for rendering this month with iteration.
- The first day of next month: needed to highlight the weekend of next month.
I made a function that would process these four dates when inputted a specific Date.
The function bundles these four dates into an object and returns it. It takes a Date object as its argument, and in this calendar that's the Date for "today."
2-2. Create getCalendarHTML
Now let's actually draw the calendar. getCalendarHTML returns the calendar's contents as HTML. It gets a bit bulky, so here's the skeleton first.
First, a row at the top for the days of the week. The const from earlier keeps the magic number out.
Then last month. If this month starts on a Wednesday, this loop fills in last month's Sunday, Monday, and Tuesday. Sundays get the sun class.
This month works the same way. Today gets the today class and a "today" label, and Saturdays and Sundays get sat and sun.
Finally, draw the days of the next month in the remaining cells.
3. Writing CSS
3-1. Using display: grid
display: grid lays an element's children out neatly in a grid, like a table.
grid-template-columnssets how the columns are laid out.1frmeans one fraction, and it's written 7 times, so you get 7 columns of equal width.grid-template-rowssets row sizes. There's only one3remhere, so only the first row is 3rem.grid-auto-rowssets the size of every row after that. It says6rem, so the rest are 6rem.
The rest is plain styling.
- When you draw a table, you want every cell wrapped in the same border, like Excel. But sometimes only the outermost cells end up with thinner lines, because in HTML terms the border only goes on
thandtd. - I like to put n px on every cell border and n px on the table border. That gives you a uniform
2n pxborder everywhere.
3-2. Highlighting Saturdays, Sundays, and today
I felt that
- At first I got a little lost hooking up JS to "initialize" the calendar. I had attached
renderCalendarat the top ofbody. The DOM runs top to bottom, sorenderCalendarran before the#Appdiv existed and couldn't find it. - I also forgot how to get what I'd built in JS onto the screen. The answer was simple. Grab the app with querySelector in the JS that plays the role of index.js, and set its innerHTML.
- The Woowa Tech Camp project had magic numbers. This time I took them out for readability.
- The Woowa Tech Camp project was object-oriented JavaScript (a Singleton, to be precise). This time it's small functions.
- I tried to use ES6+ syntax, like template literals with backticks and destructuring what processDate returns. Mostly let and const, too.
- I wish I could have made
getCalendarHTMLa bit shorter.