@uxf/datepicker

A set of React hooks to create an awesome datepicker.

Usage no npm install needed!

<script type="module">
  import uxfDatepicker from 'https://cdn.skypack.dev/@uxf/datepicker';
</script>

README

@uxf/datepicker

A set of React hooks to create an awesome datepicker.

Quick start

Main logic component

export const DatePicker: FC = () => {
    // prepare state to handle selected date
    const [selectedDate, setSelectedDate] = useState<OnDateChangeType>(null);

    const {
        activeMonths,
        firstDayOfWeek,
    } = useDatePicker({
        selectedDate,
        minBookingDate: new Date(),
        onDateChange: setSelectedDate,
    });

    // you can use DatePickerContext that helps you avoid passing callbacks throught components
    return (
        <DatePickerContext.Provider value={{ addPropsHere }}>
              {activeMonths.map(month => (
                    <DateRangePickerMonth
                        firstDayOfWeek={firstDayOfWeek}
                        key={`${month.year}-${month.month}`}
                        month={month.month}
                        year={month.year}
                    />
              ))}
        </DatePickerContext.Provider>
    );
};

Month component

export const DateRangePickerMonth: FC<UseMonthProps> = ({
    firstDayOfWeek,
    month,
    year,
}) => {
    const { days, monthLabel } = useMonth({
        year,
        month,
        firstDayOfWeek,
    });

    return (
        <div>
            <p>{monthLabel}</p>
            <div style={{ display: "grid" }}>
                {days.map((day, index) => {
                    return <DateRangePickerDay date={day.date} key={day.dayLabel + index} day={day.dayLabel} />;
                })}
            </div>
        </div>
    );
};

Day component

export const DateRangePickerDay: FC<{ day: string; date: Date }> = ({ day, date }) => {
    const dayRef = useRef(null);
    const {
        focusedDate,
        isDateFocused,
        isDateSelected,
        isDateHovered,
        isDateBlocked,
        onDateSelect,
        onDateFocus,
        onDateHover,
    } = useContext(DatePickerContext);

    const { disabledDate, isSelected, isWithinHoverRange, onClick, isToday } =
        useDay<HTMLDivElement>({
            date,
            dayRef,
            focusedDate,
            isDateFocused,
            isDateSelected,
            isDateHovered,
            isDateBlocked,
            onDateFocus,
            onDateSelect,
            onDateHover,
        });

    if (!day) {
        return <div />;
    }

    return (
        <button
            type="button"
            ref={dayRef}
            onClick={onClick}
            className= {clsx({
                "day__disabled": disabledDate,
                "day__selected": isSelected,
                "day__today": isToday,
            })}
        >
            {day}
        </button>
    );
};

API

useDatePicker()

UseDatePickerProps

name type required default description
firstDayOfWeek FirstDayOfWeek 0
initialVisibleMonth Date
isDateBlocked (date: Date) => boolean () => false
maxBookingDate Date
minBookingDate Date
numberOfMonths number 1
onDateChange (data: OnDateChangeType): void yes
selectedDate Date \| null yes
unavailableDates Date[] []

UseDatePickerReturnType

name type description
canGoToMonth (month: Date) => boolean
canGoToNextMonth boolean
canGoToNextYear boolean
canGoToPrevMonth boolean
canGoToPrevYear boolean
canGoToYear (month: Date) => boolean
goToDate (date: Date) => void
goToNextMonths () => void
goToNextMonthsByOneMonth () => void
goToNextYear () => void
goToPrevMonths () => void
goToPrevMonthsByOneMonth () => void
goToPrevYear () => void
activeMonths MonthType[]
firstDayOfWeek FirstDayOfWeek
focusedDate Date \| null
hoveredDate Date \| null
isDateBlocked (date: Date) => boolean
isDateFocused (date: Date) => boolean
isDateHovered (date: Date) => boolean
isDateSelected (date: Date) => boolean
numberOfMonths number
onDateFocus (date: Date) => void
onDateHover (date: Date \| null) => void
onDateSelect (date: Date) => void
onResetDates () => void

useDateRangePicker()

UseDateRangePickerProps

name type required default description
changeActiveMonthOnSelect boolean false
endDate Date \| null yes
exactMinBookingDays boolean false
firstDayOfWeek FirstDayOfWeek 0
focusedInput FocusedInput yes startDate
initialVisibleMonth Date
isDateBlocked (date: Date) => boolean () => false
maxBookingDate Date
minBookingDate Date
minBookingDates number 1
numberOfMonths number 2
onDatesChange (data: OnDatesChangeType): void yes
startDate Date \| null yes
unavailableDates Date[] []

UseDateRangePickerReturnType

name type description
canGoToMonth (month: Date) => boolean
canGoToNextMonth boolean
canGoToNextYear boolean
canGoToPrevMonth boolean
canGoToPrevYear boolean
canGoToYear (month: Date) => boolean
goToDate (date: Date) => void
goToNextMonths () => void
goToNextMonthsByOneMonth () => void
goToNextYear () => void
goToPrevMonths () => void
goToPrevMonthsByOneMonth () => void
goToPrevYear () => void
activeMonths MonthType[]
firstDayOfWeek FirstDayOfWeek
focusedDate Date \| null
hoveredDate Date \| null
isDateBlocked (date: Date) => boolean
isDateFocused (date: Date) => boolean
isDateHovered (date: Date) => boolean
isDateSelected (date: Date) => boolean
isEndDate (date: Date) => boolean
isStartDate (date: Date) => boolean
numberOfMonths number
onDateFocus (date: Date) => void
onDateHover (date: Date \| null) => void
onDateSelect (date: Date) => void
onResetDates () => void

useDecade()

UseDecadeProps

name type required default description
decadeLabelFormat (start: Date, end: Date) => string
year number yes
yearLabelFormat 'date: Date) => string

UseDecadeReturnType

name type description
years { yearLabel : string; date: Date }[]
decadeLabel string

useYear()

UseYearProps

name type required default description
year number yes
yearLabelFormat (date: Date) => string
monthLabelFormat (date: Date) => string

UseYearReturnType

name type description
months { monthLabel : string; date: Date }[]
yearLabel string

useMonth()

UseMonthProps

name type required default description
year number yes
month number yes
firstDayOfWeek FirstDayOfWeek 0
dayLabelFormat (date: Date) => string
weekdayLabelFormat (date: Date) => string
monthLabelFormat (date: Date) => string

UseMonthReturnType

name type description
days {currentMonth: boolean; dayLabel: string; date: Date })[]
monthLabel string
weekdayLabels string[]

useDay()

UseDayProps

name type required default description
date Date yes
dayRef RefObject
focusedDate Date \| null yes
isDateBlocked (date: Date) => boolean yes
isDateFocused (date: Date) => boolean yes
isDateHovered (date: Date) => boolean yes
isDateSelected (date: Date) => boolean yes
onDateFocus (date: Date) => void yes
onDateHover (date: Date) => void yes
onDateSelect (date: Date) => void yes

UseDayReturnType

name type description
disabledDate boolean
isHovered boolean
isSelected boolean
isToday boolean
isWithinHoverRange boolean
onClick () => void
onKeyDown (e: KeyboardEvent) => void
onMouseEnter () => void
tabIndex number

Known issues

  • keyboard navigation doesn't work for year and decade view
  • the demo needs a little more love