LaniusExcubitor
LaniusExcubitor

Reputation: 346

Open Dialog instead of Popper in desktop MUI 5 DatePicker

I want the MUI v5 DatePicker (@mui/lab 5.0.0-alpha-51) to behave like the DesktopDatePicker (allowing to directly edit the date in the textbox). But when clicking on the calendar icon, I want to open the picker dialog, just like when clicking the MobileDatePicker.

I tried using the MobileDatePicker and added endAdornment to the InputProps to just get the calendar icon to draw. But this wasn't working.

Perhaps to put it more clearly: I want the DesktopDatePicker to open the Dialog of the MobileDatePicker when the user clicks on the calendar icon.

Is there a way to achieve this hybrid behavior?

Upvotes: 5

Views: 4349

Answers (1)

NearHuscarl
NearHuscarl

Reputation: 81370

If you have a look at MobileWrapper and DesktopWrapper definitions, you'll see that they use different components to display the picker (the former uses modal, the latter uses popover) and there is no way to swap it using the props provided by the picker component, but you also know where the internal modal comes from, so you can grab it:

import PickersModalDialog from "@mui/lab/internal/pickers/PickersModalDialog";

In this section, you can see that MUI exposes the StaticDatePicker which uses the internal Picker component that both the desktop and mobile pickers utilize, in case you want to build your own custom popup/modal, this is exactly what you want here, so grab this one too:

import StaticDatePicker from '@mui/lab/StaticDatePicker';

The next step is to integrate and make them work together, we have the DesktopDatePicker because you want to edit the TextField, the PickersModalDialog to display the StaticDatePicker in a modal. To do that you need to do the following things:

  • (1) Disable the popover picker from the DesktopDatePicker or we'll have 2 pickers show up at the same time.
  • (2) Control the DesktopDatePicker date value. The DesktopDatePicker requests to change the value when the user edits the TextField.
  • (3) Control the StaticDatePicker date value. The StaticDatePicker requests to change the value when the user picks a date in the modal.
  • (4) Control the PickersModalDialog open state by overriding the props in the step below.
  • (5) Add the required props in PickersModalDialog:
    • onAccept: When the user clicks the OK button.
    • onClear: When the user clicks the CANCEL button.
    • onSetToday: When the user clicks the TODAY button. Only available in MobileDatePicker, if you want to display it, set showTodayButton in PickersModalDialog.
    • onDismiss: When the dialog wants to close itself (for example when the user clicks outside the modal)

Putting it together, we'll have something like below:

const [value, setValue] = React.useState<Date | null>(() => new Date()); // (2)
const [tempValue, setTempValue] = React.useState<Date | null>(null); // (3)
const [open, setOpen] = React.useState(false); // (4)

return (
  <>
    <DesktopDatePicker
      label="For desktop"
      value={value}
      open={false} // (1)
      onChange={(newValue) => setValue(newValue)}
      onOpen={() => {
        setTempValue(value);
        setOpen(true);
      }}
      renderInput={(params) => <TextField {...params} />}
    />
    <PickersModalDialog
      showTodayButton
      open={open}
      // (5)
      onAccept={() => {
        setValue(tempValue);
        setOpen(false);
      }}
      onSetToday={() => {
        setValue(new Date());
        setOpen(false);
      }}
      onDismiss={() => setOpen(false)}
      onClear={() => setOpen(false)}
    >
      <StaticDatePicker
        displayStaticWrapperAs="mobile"
        value={tempValue}
        onChange={(newValue) => setTempValue(newValue)}
        renderInput={(params) => <TextField {...params} />}
      />
    </PickersModalDialog>
  </>
);

Live Demo

Codesandbox Demo

Upvotes: 7

Related Questions