Machine Coding
Calendar
Master building a monthly Calendar component in React, covering dynamic date grid generation, month navigation, date highlighting, and event marker overlays.
1. Learning Objectives
In this challenge, you will build a monthly Calendar component from scratch. By the end of this guide, you will be able to:
- Generate a dynamic grid of dates for any given month using the JavaScript
DateAPI. - Handle previous/next month navigation by shifting the viewed month.
- Highlight today's date and allow users to select a specific date.
- Display trailing days from the previous and next months to fill a complete 6-row grid.
- Add event markers on specific dates.
2. Overview
A Calendar is a classic machine coding challenge that tests your ability to work with the JavaScript Date API, generate grid layouts dynamically, and manage multiple derived values (month name, year, number of days, starting weekday). Unlike most machine coding challenges, the calendar is primarily a computation problem, not a data management one.
3. Why This Challenge Matters
Calendar components teach important date computation patterns:
- Date API Mastery: Working with
new Date(year, month, 0).getDate()to get days-in-month, andnew Date(year, month, 1).getDay()to get the starting weekday, are core techniques used in scheduling UIs, booking systems, and date pickers. - Grid Layout Generation: Building a 7-column grid dynamically from computed data teaches you how to transform derived values into visual layouts.
4. Real-World Analogy
Think of building a Calendar like printing a wall calendar page:
- The Grid: A wall calendar always has 7 columns (Sun–Sat) and 5 or 6 rows. You need to figure out which day of the week the 1st falls on to start printing numbers in the correct cell.
- Trailing Days: The gray numbers at the beginning (from last month) and end (from next month) fill the empty cells so the grid is always a perfect rectangle.
- Flipping Pages: Pressing "Next" tears off the current month and shows the next one. The entire grid is regenerated for the new month/year combination.
5. Core Concepts
Below are the key Date API methods used for calendar grid generation:
| Operation | Code | Explanation |
|---|---|---|
| Days in month | new Date(year, month + 1, 0).getDate() |
Day 0 of the next month is the last day of the current month. |
| First day weekday | new Date(year, month, 1).getDay() |
Returns 0 (Sun) through 6 (Sat) for the 1st of the month. |
| Month name | new Date(year, month).toLocaleString('default', { month: 'long' }) |
Returns the full month name for the given month index. |
| Today check | day === today.getDate() && month === today.getMonth() && year === today.getFullYear() |
Compares all three components to determine if a cell represents today. |
6. Syntax & API Reference
This example shows how to generate the grid cells array for a given month:
7. Visual Diagram
This diagram shows how the calendar grid is constructed:
8. Live Example — Full Working Code
Below is a complete HTML page demonstrating a monthly calendar with navigation, today highlight, date selection, and event markers:
What just happened? The generateCells function computes a 42-cell array (6 rows × 7 columns) for any given month/year combination. It calculates the starting weekday, fills in trailing days from the previous month, the current month's dates, and leading days from the next month. Navigation buttons shift the currentMonth and currentYear state, triggering a new grid computation via useMemo.
9. Interactive Playground
Try It Yourself Challenges:
- Add a date range selector: let the user click a start date and an end date, highlighting all dates in between.
- Add an "Add Event" form: clicking a date opens a small input where the user can type an event title to create a new event marker.
10. Common Mistakes
| Mistake | Why it happens | Wrong | Correct |
|---|---|---|---|
| Off-by-one month errors | JavaScript months are 0-indexed (January = 0), but developers often pass 1-indexed month numbers to the Date constructor. |
new Date(2026, 7, 1) for July (returns August 1st) |
new Date(2026, 6, 1) for July (month index 6) |
| Inconsistent grid sizes | Not padding with trailing/leading days creates grids with 4, 5, or 6 rows, causing the layout to jump in height when navigating months. | Only rendering current month's days (28–31 cells) | Always rendering exactly 42 cells (6 rows × 7 columns) |
11. Best Practices
- Always generate 42 cells: A consistent 6-row × 7-column grid prevents layout shifts when navigating between months with different starting weekdays.
- Use
useMemofor grid generation: Wrap thegenerateCellscomputation inuseMemokeyed on[year, month]to avoid unnecessary recalculations. - Handle year boundaries: When navigating from January to December (or vice versa), remember to increment/decrement the year alongside the month.
- Use CSS Grid for the layout:
grid-template-columns: repeat(7, 1fr)is the cleanest approach for a 7-column calendar grid.
12. Browser Compatibility/Requirements
This project uses the JavaScript Date API and CSS Grid, both of which are supported in all modern browsers (Chrome 57+, Firefox 52+, Safari 10.1+, Edge 16+).
13. Interview Questions
Q1: How does new Date(year, month + 1, 0).getDate() return the number of days in a month?
Answer:
Day 0 of any month is defined as the last day of the previous month. So new Date(2026, 8, 0) (day 0 of September) returns August 31st. Calling .getDate() on this returns 31, which is the number of days in August.
Q2: Why should you compare all three components (day, month, year) when checking if a cell is "today"?
Answer: Comparing only the day number would highlight day 15 in every month, not just today's month. Comparing day and month would highlight it in every year. You must compare all three components — day, month, and year — to uniquely identify today's date.
14. Debugging Exercise
Identify why navigating from January to December by clicking "Previous" jumps to December of the same year instead of the previous year:
Diagnosis: When crossing the January/December boundary, the month is set to 11 (December) but the year is not decremented. The user sees December of the current year instead of December of the previous year.
Fix: Decrement the year when wrapping from January to December:
15. Practice Exercises
Exercise 1: Week view mode
Add a toggle button that switches the calendar between "Month View" (the default 42-cell grid) and "Week View" (showing only 7 cells for the current week, with hour-by-hour time slots).
16. Scenario-Based Challenge
The multi-timezone calendar challenge:
You are building a meeting scheduler for a global team. Users in different time zones see the same calendar, but event times must be displayed in each user's local time zone. Describe how you would store event times (hint: UTC), display them in the user's local zone, and handle edge cases like daylight saving time transitions that can shift events across day boundaries.
17. Quick Quiz
Q1: Why do we generate exactly 42 cells (6 rows × 7 columns) for every month?
A) Because every month has exactly 42 days
B) Because it ensures a consistent grid height, preventing layout shifts when navigating between months
C) Because the Date API requires a 42-element array
Answer: B — Months have between 28–31 days and start on different weekdays. A fixed 42-cell grid accommodates all possible month configurations without changing the calendar's height.
18. Summary & Key Takeaways
- Use
new Date(year, month + 1, 0).getDate()to get the number of days in a month. - Use
new Date(year, month, 1).getDay()to determine the starting weekday. - Always generate a fixed 42-cell grid for consistent layout.
- Handle year boundaries when navigating across January/December.
- Compare all three date components (day, month, year) when checking for "today".
19. Cheat Sheet
| Operation | Syntax Pattern |
|---|---|
| Days in month | new Date(year, month + 1, 0).getDate() |
| First weekday | new Date(year, month, 1).getDay() |
| Month name | date.toLocaleString('default', { month: 'long' }) |
| CSS Grid layout | grid-template-columns: repeat(7, 1fr) |