Simple Calendar

Creating a Calendar component in React: A Step-by-Step Guide

Create a react app and add these dependencies.

1 yarn add date-fns

I'm utilizing Tailwind CSS, but feel free to use it as well or create your own styles, styled components, etc.

Lets get the dates in a month.

Each calendar consists of seven days per week and is designed to showcase six weeks. It's acceptable for some of the displayed weeks not to align with the current month.

Let's explore how to retrieve all the dates for a specified month using date-fns.

1//array to hold all the dates
2const dates = [];
3//Get the start day of the month
4const startCal = startOfWeek(startOfMonth(date));
5
6//add 6 weeks to the start date to get the end of this calendar view
7const endCal = addWeeks(startCal, 6);
8
9let theDate = startCal;
10do {
11 dates.push(theDate);
12 //add a day
13 theDate = addDays(theDate, 1);
14} while (theDate < endCal); //check if theDate is within this calendar

Our main Calendar component

Lets design our main calendar component. I am using tailwind css, feel free to use it ir create your own styles.

1<div className='flex justify-center'>
2 <div className='border-solid border-amber-500 border-2 p-2 rounded-xl'>
3 <div className='flex items-center p-2'>Our Header goes here</div>
4 <div className='flex flex-wrap w-[336px]'>Our Body goes here</div>
5 </div>
6</div>
Our Header goes here
Our Body goes here

Lets build the Header

We will ad a left arrow button to move to last month, a label to display month and year, and a right arrow button to move to next month

1<div className='flex justify-center'>
2 <div className='border-solid border-amber-500 border-2 p-2 rounded-xl'>
3 <div className='flex items-center p-2'>
4 <button onClick={goBack}>
5 <ArrowLeftIcon width={24} />
6 </button>
7 <div className='flex-1 text-center'> {format(date, 'MMM yyyy')}</div>
8 <button onClick={goNext}>
9 <ArrowRightIcon width={24} />
10 </button>
11 </div>
12 <div className='flex flex-wrap w-[336px]'>Our Body goes here</div>
13 </div>
14</div>
Dec 2023
Our Body goes here

Lets build the body

Now lets create a parent div with a flex layout which wraps and has a width of 48 * 7 cards = 336px

1<div className='flex flex-wrap w-[336px]'>
2 {calDates.map((d, i) => (
3 <div
4 className={`cursor-pointer border-2 border-base-400 border-solid p-1 w-6 h-6 text-center ${
5 d.isInMonth ? 'bg-red-100/50 hover:bg-red-100' : ''
6 }`}
7 key={i}
8 >
9 {d.date.getDate()}
10 </div>
11 ))}
12</div>

Putting it all together

1import { useCallback, useMemo, useState } from 'react';
2import {
3 startOfWeek,
4 format,
5 addWeeks,
6 startOfMonth,
7 addDays,
8 addMonths,
9} from 'date-fns';
10
11import { ArrowLeftIcon, ArrowRightIcon } from '@heroicons/react/24/solid';
12
13const today = new Date();
14export default function Calendar() {
15 const [date, setDate] = useState(today);
16
17 const calDates = useMemo(() => {
18 const dates = [];
19 const startCal = startOfWeek(startOfMonth(date));
20 const endCal = addWeeks(startCal, 6);
21
22 let theDate = startCal;
23
24 do {
25 dates.push({
26 date: theDate,
27 isInMonth: theDate.getMonth() === date.getMonth(),
28 });
29 theDate = addDays(theDate, 1);
30 } while (theDate < endCal);
31 return dates;
32 }, [date]);
33
34 const goBack = () => {
35 setDate((d) => addMonths(d, -1));
36 };
37
38 const goNext = () => {
39 setDate((d) => addMonths(d, 1));
40 };
41
42 return (
43 <div className='flex justify-center'>
44 <div className='border-solid border-red-500 border-2 p-2 rounded-xl'>
45 <div className='flex items-center p-2'>
46 <button onClick={goBack}>
47 <ArrowLeftIcon className={'w-5'} />
48 </button>
49 <div className='flex-1 text-center'> {format(date, 'MMM yyyy')}</div>
50 <button onClick={goNext}>
51 <ArrowRightIcon className={'w-5'} />
52 </button>
53 </div>
54 <div className='flex flex-wrap w-[336px]'>
55 {calDates.map((d, i) => (
56 <div
57 className={`cursor-pointer border-2 border-base-400 border-solid p-1 w-6 h-6 text-center ${
58 d.isInMonth ? 'bg-red-100/50 hover:bg-red-100' : ''
59 }`}
60 key={i}
61 >
62 {d.date.getDate()}
63 </div>
64 ))}
65 </div>
66 </div>
67 </div>
68 );
69}

Demo

Aug 2024
Sun
Mon
Tue
Wed
Thu
Fri
Sat
28
29
30
31
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
1
2
3
4
5
6
7

Conclusion

Happy coding.. In next article we will build a calendar year component.