jingwei jiang
jingwei jiang

Reputation: 39

Material-UI DateCalendar Closes When Interacting with Year/Month Dropdowns in React

I am working on a React component that uses Material-UI's DateCalendar. The component includes an input field that, when clicked, opens a date picker. The date picker should remain open while the user interacts with it, and when user click somewhere outside the datepicker, the datepicker should be closed.

My current solution is from How can I prevent onBlur event from firing?. It works fine in most cases. When user interacts with most of the area of datepicker, the datepicker remains open, when user click outside of the datepicker, the datepicker closed.

However, I am encountering an issue where the date picker closes when the user interacts with the year or month dropdown menus.

My code:

import { DateCalendar, LocalizationProvider } from "@mui/x-date-pickers";
import { AdapterDayjs } from "@mui/x-date-pickers/AdapterDayjs";
import { useState } from "react";

function App() {
  const [open, setOpen] = useState(false);

  const handleClick = () => {
    setOpen(true);
  };

  const handleBlur = () => {
    setOpen(false);
  };

  const handleMouseDown = (event) => {
    event.preventDefault();
  };

  return (
    <>
      <input id="dateInput" onClick={handleClick} onBlur={handleBlur} />
      {open ? (
        <LocalizationProvider dateAdapter={AdapterDayjs}>
          <DateCalendar onMouseDown={handleMouseDown} />
        </LocalizationProvider>
      ) : null}
    </>
  );
}

export default App;

What I expected:

The date picker should remain open while the user interacts with it, and when user click somewhere outside the datepicker, the datepicker should be closed.

Upvotes: 0

Views: 52

Answers (1)

Roman Nikolaev
Roman Nikolaev

Reputation: 33

This code works as expected. I hope it will help you.

import { DateCalendar, LocalizationProvider } from "@mui/x-date-pickers";
import { AdapterDayjs } from "@mui/x-date-pickers/AdapterDayjs";
import { useEffect, useRef, useState } from "react";

function App() {
  const [open, setOpen] = useState(false);
  
  //added ref for control calendar component
  const calendarRef = useRef();

  const handleClick = () => {
    setOpen(true);
  };

  const handleBlur = () => {
    setOpen(false);
  };

  useEffect(() => {
    function handleClickOutside(event) {
      //check if calendarRef is valid and the user clicked outside of the calendar, 
      //we can close it
      if (calendarRef.current && !calendarRef.current.contains(event.target)) {
        handleBlur();
      }
    }
    //event added to entire document to control any user clicks
    document.addEventListener("mousedown", handleClickOutside);
    return () => {
      document.removeEventListener("mousedown", handleClickOutside);
    };
  }, [calendarRef, handleBlur]);

  return (
    <>
      <input id="dateInput" onClick={handleClick} />
      {open ? (
        <LocalizationProvider dateAdapter={AdapterDayjs}>
          <DateCalendar ref={calendarRef} />
        </LocalizationProvider>
      ) : null}
    </>
  );
}

export default App;

Upvotes: 1

Related Questions