Each year the ⚛️ React community is becoming bigger and bigger.
And with this growth, we get more and more tools to achieve our goals and needs. Despite this incredible variety, it is hard to get what you want.
Let's dive into the problem:
And it is just by picking a date picker 🗓.
The solution to all of these 👆 problems could be a headless-UI component like @rehookify/datepicker
Main features and pros:
toLocaleDateString
and `toLocaleTimeString`
The main drawback is that you need to style everything by yourself. But, with modern CSS
layout techniques like grid
and flex
, it is an easy and fun thing to do. It means no drawbacks at all 😅
By using @rehookify/datepicker you can pick a modular or all-in-one approach.
The example below will give you a calendar with multiple date selections 👇
import { useState } from 'react';
import { useDatePickerState, useCalendars } from '@rehookify/datepicker';
const DatePicker = () => {
const [selectedDates, onDatesChange] = useState<Date[]>([]);
const dpState = useDatePickerState({
selectedDates,
onDatesChange,
dates: { toggle: true, mode: 'multiple' },
});
const { calendars, weekDays } = useCalendars(dpState);
const { month, year, days } = calendars[0];
return (
<section>
<header>
<div>
<p>{month} {year}</p>
</div>
<ul>
{weekDays.map((day) => (
<li key={`${month}-${day}`}>{day}</li>
))}
</ul>
</header>
<ul>
{days.map((dpDay) => (
<li key={`${month}-${dpDay.day}`}>
<button>{dpDay.day}</button>
</li>
))}
</ul>
</section>
);
}
In case you don't want to pass any parameters 💆♂️ or want to split components, you can use Context implementation.
The example below results in the calendar with date range selections 👇
import { useState } from 'react';
import {
DatePickerStateProvider,
useContextCalendars,
useContextDaysPropGetters,
useContextTime,
useContextTimePropGetters,
} from '@rehookify/datepicker';
const DatePicker = () => {
const { calendars, weekDays } = useContextCalendars();
const { dayButton } = useContextDaysPropGetters();
const { year, month, days } = calendars[0];
return (
<main>
<header>
<div>
<p>{month} {year}</p>
</div>
<ul>
{weekDays.map((day) => (
<li key={`${month}-${day}`}>{day}</li>
))}
</ul>
</header>
<ul>
{days.map((dpDay) => (
<li key={`${month}-${dpDay.day}`}>
<button {...dayButton(dpDay)}>{dpDay.day}</button>
</li>
))}
</ul>
</main>
)
}
const TimePicker = () => {
const { time } = useContextTime();
const { timeButton } = useContextTimePropGetters();
return (
<ul>
{time.map((t) => (
<li key={t.$date.toString()}>
<button {...timeButton(t)}>{t.time}</>
</li>
))}
</ul>
)
}
const App = () => {
const d = new Date();
const [selectedDates, onDatesChange] = useState<Date[]>([d]);
return (
<DatePickerStateProvider
config={{
selectedDates,
focusDate: d,
onDatesChange,
dates: { mode: 'multiple' },
}}
>
<section>
<DatePicker />
<TimePicker />
</section>
</DatePickerStateProvider>
);
}
The calendar with date selection and month pagination 👇
import { MouseEvent, useState } from 'react';
import { useDatePicker } from '@rehookify/datepicker';
const DatePicker = () => {
const [selectedDates, onDatesChange] = useState<Date[]>([]);
const {
data: { weekDays, calendars },
propGetters: {
dayButton,
previousMonthButton,
nextMonthButton,
},
} = useDatePicker({
selectedDates,
onDatesChange,
});
// calendars[0] is always present, this is an initial calendar
const { year, month, days } = calendars[0];
const onDayClick = (evt: MouseEvent<HTMLElement>, date: Date) => {
// In case you need any action with evt
evt.stopPropagation();
// In case you need any additional action with date
console.log(date);
}
// selectedDates is an array of dates
// formatted with date.toLocaleDateString(locale, options)
return (
<section>
{selectedDates.length > 0 && <h1>{selectedDates[0]}</h1>}
<header>
<div>
<button {...previousMonthButton()}><</button>
<p>{month} {year}</p>
<button {...nextMonthButton()}>></button>
</div>
<ul>
{weekDays.map((day) => (
<li key={`${month}-${day}`}>{day}</li>
))}
</ul>
</header>
<ul>
{days.map((dpDay) => (
<li key={`${month}-${dpDay.day}`}>
<button
{...dayButton(dpDay, { onClick: onDayClick })}
>
{dpDay.day}
</button>
</li>
))}
</ul>
</section>
)
}
import { useState } from 'react';
import {
DatePickerProvider,
useDatePickerContext,
} from '@rehookify/datepicker';
const DatePicker = () => {
const {
data: { weekDays, calendars, years, months },
} = useDatePickerContext();
const { year, month, days } = calendars[0];
return (
<section>
<header>{month} {year}</header>
...
</section>
)
}
const App = () => {
const [selectedDates, onDatesChange] = useState<Date[]>([]);
return (
<DatePickerProvider
config={{
selectedDates,
onDatesChange,
dates: { mode: 'range' },
}}
>
<DatePicker />
</DatePickerProvider>
);
}
@rehookify/datepicker will help you create a date picker that suits your need and tech stack. Its modular design will save as many bytes for your app as possible.
Image by Anton Lapko