How To Create a React Week Picker Using React Suite DatePicker?
In this tutorial, we're going to see how we can create a React Week Picker by customizing the React Suite Datepicker. To do so we will use the options of the Datepicker to convert it to a Week Picker alongside with CSS customizations.
For the final code click here.
1. Project Setup
So, let's start by creating a new folder and open it in VS code, then open a new terminal to create a new react app. To do so I will use Vite instead of create-react-app because I find it faster especially during development.
So let's type npm create vite .
to create a vite app in the current directory. You'll then be prompted to select the technology so choose React and we will stick with javascript for this tutorial.
Now you have to run npm install
. Once the dependencies are installed, just run npm run dev
to start the development server.
2. Week Picker Component
2.1 Files Creation
In the src folder create a components folder in which I will create the Week Picker component, simply type rafce to initialize a functional React component, (if you don't have the rafce shortcut you have to install the react snippets extension in your VS code).
/***** WeekPicker.jsx *****/
import React from 'react'
const WeekPicker = () => {
return (
<div>WeekPicker</div>
)
}
export default WeekPicker
Then let's import our component in the App.jsx component.
Now we have to install some dependencies so I'll open another terminal and type npm install rsuite moment
.
Let's modify our WeekPicker.jsx as follow:
/***** WeekPicker.jsx *****/
import React from 'react'
import DatePicker from 'rsuite/DatePicker';
import 'rsuite/dist/rsuite.min.css';
const WeekPicker = () => {
return (
<div className='WeekPicker'>
<h1>Week Picker</h1>
<DatePicker
placeholder='Week picker'
/>
</div>
)
}
export default WeekPicker
Let's create a CSS file that we will use to customize the WeekPicker component and then import it in our WeekPicker.jsx.
/***** WeekPicker.css *****/
.WeekPicker{
margin-left: 10px;
}
2.2 React Suite DatePicker
Now let's go to the docs of React Suite DatePicker and scroll down to the props section. The first prop we will use is isoweek prop to make the week start from Monday and finish on Sunday, and the second is showWeekNumbers to display week numbers for each week.
/***** WeekPicker.jsx *****/
import React from 'react'
import DatePicker from 'rsuite/DatePicker';
import 'rsuite/dist/rsuite.min.css';
const WeekPicker = () => {
return (
<div className='WeekPicker'>
<h1>Week Picker</h1>
<DatePicker
placeholder='Week picker'
isoWeek
showWeekNumbers
/>
</div>
)
}
export default WeekPicker
Once you add these props you will notice that week numbers are now displayed but let's make them look better. Modify the WeekPicker.css as follow:
/***** WeekPicker.css *****/
.WeekPicker{
margin-left: 10px;
}
.rs-picker-date-menu .rs-calendar-table-cell-week-number{
background-color: black;
color: white;
padding: 10px;
font-weight: bold;
}
So I added some basic styling to the week numbers and they look much better already.
2.3 Add Hover Effect for the full week
Now we want to add this hover effect for the entire week and not just a single day so let's find the CSS code.
/***** WeekPicker.css *****/
.WeekPicker{
margin-left: 10px;
}
.rs-picker-date-menu .rs-calendar-table-cell-week-number{
background-color: black;
color: white;
padding: 10px;
font-weight: bold;
}
.rs-picker-date-menu .rs-calendar-table-row:hover .rs-calendar-table-cell-content {
background-color: rgba(204,233,255,.5);
background-color: var(--rs-listbox-option-hover-bg);
color: #1675e0;
color: var(--rs-listbox-option-hover-text);
}
Ok as you can see now, we can hover an entire week but we don't want this effect for the day names so let's exclude them. We can use this class rs-calendar-table-header-row
to do so.
So let's modify our CSS code by adding an exception for this class. And now it works as intended.
/***** WeekPicker.css *****/
.WeekPicker{
margin-left: 10px;
}
.rs-picker-date-menu .rs-calendar-table-cell-week-number{
background-color: black;
color: white;
padding: 10px;
font-weight: bold;
}
.rs-picker-date-menu .rs-calendar-table-row:not(.rs-calendar-table-header-row):hover .rs-calendar-table-cell-content {
background-color: rgba(204,233,255,.5);
background-color: var(--rs-listbox-option-hover-bg);
color: #1675e0;
color: var(--rs-listbox-option-hover-text);
}
2.4 Add State for Week Infos
Now let's go back to our WeekPicker.jsx and add a state that will store the week infos.
const [objWeek, setObjWeek] = useState({
date: new Date(),
dateFrom: null,
dateTo: null,
weekNumber: null
});
Now at the bottom add a div and give it a className of weekInfos in which we will display informations on the selected week.
/***** WeekPicker.jsx *****/
import React, { useState } from 'react'
import DatePicker from 'rsuite/DatePicker';
import 'rsuite/dist/rsuite.min.css';
import './WeekPicker.css';
const WeekPicker = () => {
const [objWeek, setObjWeek] = useState({
date: new Date(),
dateFrom: null,
dateTo: null,
weekNumber: null
});
return (
<div className='WeekPicker'>
<h1>Week Picker</h1>
<DatePicker
placeholder='Week picker'
isoWeek
showWeekNumbers
/>
<div className='weekInfos'>
<div>
<span>Week Number : </span>
<b>{objWeek.weekNumber}</b>
</div>
<div>
<span>Start of Week : </span>
<b>{objWeek.dateFrom?.toDateString()}</b>
</div>
<div>
<span>End of Week : </span>
<b>{objWeek.dateTo?.toDateString()}</b>
</div>
</div>
</div>
)
}
export default WeekPicker
Make sure to modify the CSS file as well to add some spacing to the weekInfos div.
/***** WeekPicker.css*****/
.WeekPicker{
margin-left: 10px;
}
.rs-picker-date-menu .rs-calendar-table-cell-week-number{
background-color: black;
color: white;
padding: 10px;
font-weight: bold;
}
.rs-picker-date-menu .rs-calendar-table-row:not(.rs-calendar-table-header-row):hover .rs-calendar-table-cell-content {
background-color: rgba(204,233,255,.5);
background-color: var(--rs-listbox-option-hover-bg);
color: #1675e0;
color: var(--rs-listbox-option-hover-text);
}
.WeekPicker .weekInfos{
margin-top: 20px;
}
.WeekPicker .weekInfos > div{
margin-top: 10px;
}
Now let's connect our DatePicker to our local state by specifying the value to objWeek.date. Then, we need to update our state whenever a date is selected. For that we will use the onChange callback.
To calculate the week number and dates of Start and End of a week we will use moment so let's import it.
To calculate the weekNumber we can use the isoWeek() method of moment and for dateFrom we will use the startOf('isoWeek') method that return the date of the Monday of that week. For dateTo we will use the endOf('isoWeek') method that return the date of the Sunday of that week.
Then let's update our state by calling setObjWeek.
/***** WeekPicker.jsx*****/
import React, { useState } from 'react'
import DatePicker from 'rsuite/DatePicker';
import moment from 'moment';
import 'rsuite/dist/rsuite.min.css';
import './WeekPicker.css';
const WeekPicker = () => {
const [objWeek, setObjWeek] = useState({
date: new Date(),
dateFrom: null,
dateTo: null,
weekNumber: null
});
const onChange = (date) => {
const weekNumber = moment(date).isoWeek();
const dateFrom = moment(date).startOf('isoWeek').toDate();
const dateTo = moment(date).endOf('isoWeek').toDate();
setObjWeek({
date,
dateFrom,
dateTo,
weekNumber
})
}
return (
<div className='WeekPicker'>
<h1>Week Picker</h1>
<DatePicker
placeholder='Week picker'
isoWeek
showWeekNumbers
value={objWeek.date}
onChange={onChange}
/>
<div className='weekInfos'>
<div>
<span>Week Number : </span>
<b>{objWeek.weekNumber}</b>
</div>
<div>
<span>Start of Week : </span>
<b>{objWeek.dateFrom?.toDateString()}</b>
</div>
<div>
<span>End of Week : </span>
<b>{objWeek.dateTo?.toDateString()}</b>
</div>
</div>
</div>
)
}
export default WeekPicker
And this is the result we got:
Now let's customize the value displayed to show the selected week instead of the date. To do so we can use another prop called renderValue.
/***** WeekPicker.jsx*****/
import React, { useState } from 'react'
import DatePicker from 'rsuite/DatePicker';
import moment from 'moment';
import 'rsuite/dist/rsuite.min.css';
import './WeekPicker.css';
const WeekPicker = () => {
const [objWeek, setObjWeek] = useState({
date: new Date(),
dateFrom: null,
dateTo: null,
weekNumber: null
});
const onChange = (date) => {
const weekNumber = moment(date).isoWeek();
const dateFrom = moment(date).startOf('isoWeek').toDate();
const dateTo = moment(date).endOf('isoWeek').toDate();
setObjWeek({
date,
dateFrom,
dateTo,
weekNumber
})
}
const renderValue = (date) => {
const weekNumber = moment(date).isoWeek();
const year = moment(date).year();
return `W${weekNumber}, ${year}`;
}
return (
<div className='WeekPicker'>
<h1>Week Picker</h1>
<DatePicker
placeholder='Week picker'
isoWeek
showWeekNumbers
value={objWeek.date}
onChange={onChange}
renderValue={renderValue}
/>
<div className='weekInfos'>
<div>
<span>Week Number : </span>
<b>{objWeek.weekNumber}</b>
</div>
<div>
<span>Start of Week : </span>
<b>{objWeek.dateFrom?.toDateString()}</b>
</div>
<div>
<span>End of Week : </span>
<b>{objWeek.dateTo?.toDateString()}</b>
</div>
</div>
</div>
)
}
export default WeekPicker
And here is the result after this modification:
2.5 Add Selected Week Style
The last thing I want to do is to add the selected style for the full week instead of a single date, so let's modify our WeekPicker.css as follow:
/***** WeekPicker.css*****/
.WeekPicker{
margin-left: 10px;
}
.rs-picker-date-menu .rs-calendar-table-cell-week-number{
background-color: black;
color: white;
padding: 10px;
font-weight: bold;
}
.rs-picker-date-menu .rs-calendar-table-row:not(.rs-calendar-table-header-row):hover .rs-calendar-table-cell-content {
background-color: rgba(204,233,255,.5);
background-color: var(--rs-listbox-option-hover-bg);
color: #1675e0;
color: var(--rs-listbox-option-hover-text);
}
.rs-picker-date-menu .rs-calendar-table-row:not(.rs-calendar-table-header-row):has(.rs-calendar-table-cell-selected) .rs-calendar-table-cell-content {
background-color: #3498ff;
background-color: var(--rs-bg-active);
-webkit-box-shadow: none;
box-shadow: none;
color: #fff;
color: var(--rs-calendar-date-selected-text);
}
.WeekPicker .weekInfos{
margin-top: 20px;
}
.WeekPicker .weekInfos > div{
margin-top: 10px;
}
I used a CSS selector called :has()
. This selector is not supported in the Mozilla browser for the moment.
After this modification, an entire week is now selected.
3. Conclusion
In this article, we went through the process of creating a React Week Picker by customizing the React Suite DatePicker. If you want to stay updated with our tutorials, bookmark our website. Don't forget also to check our FREE tools that will help you with your daily activities.
4. Final Code
4.1 WeekPicker.jsx
import React, { useState } from 'react'
import DatePicker from 'rsuite/DatePicker';
import moment from 'moment';
import 'rsuite/dist/rsuite.min.css';
import './WeekPicker.css';
const WeekPicker = () => {
const [objWeek, setObjWeek] = useState({
date: new Date(),
dateFrom: null,
dateTo: null,
weekNumber: null
});
const onChange = (date) => {
const weekNumber = moment(date).isoWeek();
const dateFrom = moment(date).startOf('isoWeek').toDate();
const dateTo = moment(date).endOf('isoWeek').toDate();
setObjWeek({
date,
dateFrom,
dateTo,
weekNumber
})
}
const renderValue = (date) => {
const weekNumber = moment(date).isoWeek();
const year = moment(date).year();
return `W${weekNumber}, ${year}`;
}
return (
<div className='WeekPicker'>
<h1>Week Picker</h1>
<DatePicker
placeholder='Week picker'
isoWeek
showWeekNumbers
value={objWeek.date}
onChange={onChange}
renderValue={renderValue}
/>
<div className='weekInfos'>
<div>
<span>Week Number : </span>
<b>{objWeek.weekNumber}</b>
</div>
<div>
<span>Start of Week : </span>
<b>{objWeek.dateFrom?.toDateString()}</b>
</div>
<div>
<span>End of Week : </span>
<b>{objWeek.dateTo?.toDateString()}</b>
</div>
</div>
</div>
)
}
export default WeekPicker
4.2 WeekPicker.css
.WeekPicker{
margin-left: 10px;
}
.rs-picker-date-menu .rs-calendar-table-cell-week-number{
background-color: black;
color: white;
padding: 10px;
font-weight: bold;
}
.rs-picker-date-menu .rs-calendar-table-row:not(.rs-calendar-table-header-row):hover .rs-calendar-table-cell-content {
background-color: rgba(204,233,255,.5);
background-color: var(--rs-listbox-option-hover-bg);
color: #1675e0;
color: var(--rs-listbox-option-hover-text);
}
.rs-picker-date-menu .rs-calendar-table-row:not(.rs-calendar-table-header-row):has(.rs-calendar-table-cell-selected) .rs-calendar-table-cell-content {
background-color: #3498ff;
background-color: var(--rs-bg-active);
-webkit-box-shadow: none;
box-shadow: none;
color: #fff;
color: var(--rs-calendar-date-selected-text);
}
.WeekPicker .weekInfos{
margin-top: 20px;
}
.WeekPicker .weekInfos > div{
margin-top: 10px;
}