Tan Silliksaar
Tan Silliksaar

Reputation: 179

How to enable year selection in MUI DateRangePicker calendar?

MUI DatePicker shows a little arrow next to the year and month in the calendar. Clicking on it allows selecting a year. DateRangePicker, however, does not show that option in the calendar. How to enable year selection for date ranges that include many years? Scrolling through months to go 10 years back is not very comfortable. Thank you

Upvotes: 1

Views: 206

Answers (1)

vsync
vsync

Reputation: 130521

I've tried challenging the same and after a too much wasted time, have decided to mimic the DateRangePicker by combining my desired field component and an Popover component which renders 2 date calendars components which at the end visually emulates the DateRangePicker component, which was good enough for my needs.

Below is the basis of what I did (I am using tailwindcss & dateFns lib):

DateRangePicker:

import { useCallback, useMemo, useState } from "react";
import CalendarIcon from "@mui/icons-material/Event";
import { Popover, useTheme } from "@mui/material";
import { AdapterDateFns } from "@mui/x-date-pickers-pro/AdapterDateFnsV3";
import { LocalizationProvider } from "@mui/x-date-pickers-pro/LocalizationProvider";
import { SingleInputDateRangeField } from "@mui/x-date-pickers-pro/SingleInputDateRangeField";
import type { InputFieldSize } from "../sharedInputTypes";
import DateRangePickerDates from "./components/DateRangePickerDates/DateRangePickerDates";

const DateRangePicker = ({ value, onChange, size }) => {
  const theme = useTheme();
  const [anchorEl, setAnchorEl] = useState<HTMLButtonElement | null>(null);

  const handleClick = useCallback((event: MouseEvent<HTMLButtonElement>) => {
    setAnchorEl(event.currentTarget);
  }, []);

  const handleClose = useCallback(() => {
    setAnchorEl(null);
  }, []);

  return (
    <LocalizationProvider dateAdapter={AdapterDateFns}>
      <SingleInputDateRangeField
        value={value}
        maxDate={new Date()}
        onChange={onChange}
        onClick={handleClick}
        sx={sx}
        slotProps={{
          textField: {
            InputProps: {
              endAdornment: <CalendarIcon className="opacity-50" />,
            },
          },
        }}
      />
      <Popover
        open={open}
        anchorEl={anchorEl}
        onClose={handleClose}
        anchorOrigin={{
          vertical: "bottom",
          horizontal: "left",
        }}
      >
        <DateRangePickerDates value={value} onChange={onChange} />
      </Popover>
    </LocalizationProvider>
  );
};

export default DateRangePicker;

DateRangePickerDates:

import { FC, useCallback } from "react";
import { Divider } from "@mui/material";
import { DateCalendar } from "@mui/x-date-pickers/DateCalendar";

interface DateRangePickerDatesProps {
  value: [Date | null, Date | null];
  onChange: (value: [Date | null, Date | null]) => void;
}

const DateRangePickerDates: FC<DateRangePickerDatesProps> = ({
  value,
  onChange,
}) => {
  const onCalendarChange = useCallback(
    (newValue: Date | null, index: number) => {
      if (!onChange || !value) return;

      const newRange: [Date | null, Date | null] = [...value];
      newRange[index] = newValue;

      // Validate date range
      if (newRange[0] && newRange[1]) {
        if (index === 0 && newRange[0] > newRange[1]) {
          newRange[1] = newRange[0];
        } else if (index === 1 && newRange[1] < newRange[0]) {
          newRange[0] = newRange[1];
        }
      }

      onChange(newRange);
    },
    [onChange, value]
  );

  return (
    <div className="flex">
      <DateCalendar
        format="system"
        value={value?.[0]}
        onChange={(v) => onCalendarChange(v, 0)}
      />
      <Divider orientation="vertical" flexItem />
      <DateCalendar
        format="system"
        value={value?.[1]}
        onChange={(v) => onCalendarChange(v, 1)}
      />
    </div>
  );
};

export default DateRangePickerDates;

enter image description here

Upvotes: 0

Related Questions