Migration from v7 to v8
This guide describes the changes needed to migrate the Date and Time Pickers from v7 to v8.
Introduction
This is a reference guide for upgrading @mui/x-date-pickers from v7 to v8.
Start using the new release
In package.json, change the version of the date pickers package to latest.
-"@mui/x-date-pickers": "7.x.x",
+"@mui/x-date-pickers": "latest",
-"@mui/x-date-pickers-pro": "7.x.x",
+"@mui/x-date-pickers-pro": "latest",
Since v8 is a major release, it contains changes that affect the public API.
These changes were done for consistency, improved stability and to make room for new features.
Described below are the steps needed to migrate from v7 to v8.
Package layout changes
MUI X v8 packages have been updated to use the Node.js exports field, following Material v7 package layout changes.
MUI X v8 packages are compatible with Material UI v7 out of the box. We encourage upgrading to Material UI v7 to take advantage of better ESM support.
Material UI v6 and v5 can still be used but require some additional steps if you are importing the packages in a Node.js environment. Follow the instructions in the Usage with Material UI v5/v6 guide.
Modern bundles have also been removed, as the potential for a smaller bundle size is no longer significant. If you've configured aliases for these bundles, you must remove them now.
 {
   resolve: {
     alias: {
-      '@mui/x-date-pickers': '@mui/x-date-pickers/modern',
-      '@mui/x-date-pickers-pro': '@mui/x-date-pickers-pro/modern',
     },
   },
 }
Run codemods
The preset-safe codemod will automatically adjust the bulk of your code to account for breaking changes in v8. You can run v8.0.0/pickers/preset-safe targeting only Date and Time Pickers or v8.0.0/preset-safe to target the other packages as well.
You can either run it on a specific file, folder, or your entire codebase when choosing the <path> argument.
# Date and Time Pickers specific
npx @mui/x-codemod@latest v8.0.0/pickers/preset-safe <path>
# Target the other packages as well
npx @mui/x-codemod@latest v8.0.0/preset-safe <path>
Breaking changes that are handled by this codemod are denoted by a ✅ emoji in the table of contents on the right side of the screen.
If you have already applied the v8.0.0/pickers/preset-safe (or v8.0.0/preset-safe) codemod, then you should not need to take any further action on these items.
All other changes must be handled manually.
✅ Rename date-fns adapter imports
- The - AdapterDateFnsand- AdapterDateFnsJalaliadapters have been renamed to- AdapterDateFnsV2and- AdapterDateFnsJalaliV2respectively. If you were using the old imports, you need to update them:- -import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns'; -import { AdapterDateFnsJalali } from '@mui/x-date-pickers/AdapterDateFnsJalali'; +import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFnsV2'; +import { AdapterDateFnsJalali } from '@mui/x-date-pickers/AdapterDateFnsJalaliV2';- Or consider updating the - date-fnsor- date-fns-jalalipackage to the latest version and use the updated adapters.
- The - AdapterDateFnsV3and- AdapterDateFnsJalaliV3adapters have been renamed to- AdapterDateFnsand- AdapterDateFnsJalalirespectively. If you were using the old imports, you need to update them:- -import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFnsV3'; -import { AdapterDateFnsJalali } from '@mui/x-date-pickers/AdapterDateFnsJalaliV3'; +import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns'; +import { AdapterDateFnsJalali } from '@mui/x-date-pickers/AdapterDateFnsJalali';
Components breaking changes
⚠️ Updated view selection process
The view selection process has been updated to make it clearer across all Pickers.
Only <DesktopDatePicker /> and <DesktopDateRangePicker /> maintain the previous behavior of closing after the selection is complete and switching to the end range position when the start value is selected.
In essence, the automatic range position and view switching have been removed in favor of manual confirmation.
The new default behavior for all other cases is as follows:
- Selection on a given view has to be confirmed by clicking the "Next" action button if there are other selection steps.
- The "Next" action is replaced with ""OK" if there is no next step.
- The "OK" action has to be clicked to confirm the selection and close the Picker.
Here are a few examples of how the new behavior works:
- On - <DesktopDateTimePicker />:- Previously selecting a date and then selecting all time sections automatically closed the Picker.
- Now, the user has to click "OK" to confirm the selection and close the Picker regardless of the selection process.
 
- On - <DesktopDateTimeRangePicker />:- Previously selecting a start date and then selecting all time sections automatically switched to the end date selection step. After the last end time section was selected, the Picker closed.
- Now, the user has to click "Next" to confirm the start date and time selection to get to the end date and time selection step. Clicking "OK" while on the end date and time step confirms the selection and closes the Picker.
 
- On - <MobileDateTimeRangePicker />:- Previously selecting a start date automatically switched to the start time selection step. After the last time section selection, the Picker switched to the end date step.
- Now, the user has to click "Next" to confirm the start date selection to get to the start time selection step. Clicking "Next" while on the start time step switches the Picker to the end date step.
 
⚠️ New DOM structure for the field
Before version v7.x, the fields' DOM structure consisted of an <input />, which held the whole value for the component.
Unfortunately it presented accessibility limitations, which are impossible to resolve.
Starting with version v7.x, we have introduced a new DOM structure that allows the field component to set aria attributes on individual sections, providing a far better experience on screen readers.
This approach is recommended in W3C ARIA example and is also used by native date HTML input element under the hood.
Starting with version v8.x, the new DOM structure is the default for all fields.
Fallback to the non-accessible DOM structure
<DateField enableAccessibleFieldDOMStructure={false} />
<DatePicker enableAccessibleFieldDOMStructure={false} />
<DateRangePicker enableAccessibleFieldDOMStructure={false} />
Migrate slotProps.field
When using slotProps.field to pass props to your field component,
the field consumes some props (for example shouldRespectLeadingZeros) and forwards the rest to the TextField.
- For the props consumed by the field, the behavior should remain exactly the same with both DOM structures. - Both components below respect the leading zeroes on digit sections: - <DatePicker slotProps={{ field: { shouldRespectLeadingZeros: true } }} enableAccessibleFieldDOMStructure={false} /> <DatePicker slotProps={{ field: { shouldRespectLeadingZeros: true } }} />
- For the props forwarded to the - TextField, you can have a look at the next section to see how the migration impact them.- Both components below render a small size UI: - <DatePicker slotProps={{ field: { size: 'small' } }} enableAccessibleFieldDOMStructure={false} /> <DatePicker slotProps={{ field: { size: 'small' } }} />
Migrate slotProps.textField
If you are passing props to slotProps.textField,
the PickersTextField component now receives these props and should keep working the same as before.
Both components below render a small size UI:
<DatePicker
  slotProps={{ textField: { size: 'small' } }}
  enableAccessibleFieldDOMStructure={false}
/>
<DatePicker
  slotProps={{ textField: { size: 'small' } }}
/>
Migrate slots.field
If you are passing a custom field component to your pickers, you need to create a new one that is using the accessible DOM structure.
This new component needs to use the PickersSectionList component instead of an <input /> HTML element.
You can have a look at the Using a custom input section to have a concrete example.
Migrate slots.textField
If you are passing a custom TextField component to your fields and pickers,
you need to create a new one that is using the accessible DOM structure.
You can have a look at the Wrapping PickersTextField section to have a concrete example.
Migrate the theme
If you are using the theme to customize MuiTextField,
you need to pass the same config to MuiPickersTextField:
const theme = createTheme({
  components: {
    MuiTextField: {
      defaultProps: {
        variant: 'outlined',
      },
      styleOverrides: {
        root: {
          '& .MuiInputLabel-outlined.Mui-focused': {
            color: 'red',
          },
        },
      },
    },
    MuiPickersTextField: {
      defaultProps: {
        variant: 'outlined',
      },
      styleOverrides: {
        root: {
          '& .MuiInputLabel-outlined.Mui-focused': {
            color: 'red',
          },
        },
      },
    },
  },
});
If you are using the theme to customize MuiInput, MuiOutlinedInput or MuiFilledInput,
you need to pass the same config to MuiPickersInput, MuiPickersOutlinedInput or MuiPickersFilledInput:
const theme = createTheme({
  components: {
    // Replace with `MuiOutlinedInput` or `MuiFilledInput` if needed
    MuiInput: {
      defaultProps: {
        margin: 'dense',
      },
      styleOverrides: {
        root: {
          color: 'red',
        },
      },
    },
    // Replace with `MuiPickersOutlinedInput` or `MuiPickersFilledInput` if needed
    MuiPickersInput: {
      defaultProps: {
        margin: 'dense',
      },
      styleOverrides: {
        root: {
          color: 'red',
        },
      },
    },
  },
});
If you are using the theme to customize MuiInputBase,
you need to pass the same config to MuiPickersInputBase:
const theme = createTheme({
  components: {
    MuiInputBase: {
      defaultProps: {
        margin: 'dense',
      },
      styleOverrides: {
        root: {
          color: 'red',
        },
      },
    },
    MuiPickersInputBase: {
      defaultProps: {
        margin: 'dense',
      },
      styleOverrides: {
        root: {
          color: 'red',
        },
      },
    },
  },
});
Clean the ownerState
The ownerState is an object describing the current state of a given component to let you do more advanced customization.
It is used in two different APIs:
- In the theme's styleOverrides, theownerStateis passed to the function that returns the style:
const theme = createTheme({
  components: {
    MuiDateCalendar: {
      styleOverrides: {
        root: ({ ownerState }) => ({
          /** Style based on the ownerState */
        }),
      },
    },
  },
});
- In the slotProps, theownerStateis passed to the function that returns the custom props:
<DatePicker
  slotProps={{
    actionBar: (ownerState) => ({
      /** Props based on the ownerState */
    }),
  }}
/>
Before version v8.x, the ownerState contained every prop of the component, plus some additional internal states if needed.
This presented a few problems:
- It was hard to know which ancestor defines the - ownerStateand therefore which props it contains (is the- actionBarslot handled by- DatePicker, by- DesktopDatePickeror by- PickerLayout?).
- Many properties of the - ownerStatewere not intended for public use, which complicated the evolution of the codebase. All the props received by an internal component became part of the public API, and consequently, any changes to them would have resulted in a breaking change.
- Some properties that would have been useful for customizing a component were not present if the component was not using them by default. For example, if the built-in styles for the - actionBardidn't need to know if the picker is disabled, then the- ownerStateof the- actionBardidn't contain this information.
- The naming of the props made it difficult to understand which element they applied to. If the - ownerStateof the- monthButtonslot contained- disabled, it was hard to establish whether the disabled state applied to the- monthButtonor the Picker itself.
To solve these issues, the ownerState has been reworked.
Every component's ownerState contains a shared set of properties describing the state of the picker it is in (isPickerValueEmpty, isPickerOpen, isPickerDisabled, isPickerReadOnly, pickerVariant and pickerOrientation).
Some component's ownerState contain additional properties describing their own state (isMonthDisabled for the month button, toolbarOrientation for the toolbar, isDaySelected for the day button, etc.).
⏩ Field editing on mobile Pickers
The field is now editable if rendered inside a mobile Picker.
Before version v8.x, if rendered inside a mobile Picker, the field was read-only, and clicking anywhere on it would open the Picker.
The mobile and desktop Pickers now behave similarly:
- clicking on the field allows editing the value with the keyboard
- clicking on the input adornment opens the Picker
⏩ New default fields for the range pickers
The range pickers now use single input fields by default:
- Date Range Picker: <SingleInputDateRangeField />instead of<MultiInputDateRangeField />
- Time Range Picker: <SingleInputTimeRangeField />instead of<MultiInputTimeRangeField />
- Date Time Range Picker: <SingleInputDateTimeRangeField />instead of<MultiInputDateTimeRangeField />
You can manually pass the multi input fields to your picker if you prefer them:
 import { DateRangePicker } from '@mui/x-date-pickers-pro/DateRangePicker';
+import { MultiInputDateRangePicker } from '@mui/x-date-pickers-pro/MultiInputDateRangePicker';
 <DateRangePicker
+  slots={{ field: MultiInputDateRangePicker }}
 />
If you were already using a single input field, you no longer need to manually pass it to the picker:
 import { DateRangePicker } from '@mui/x-date-pickers-pro/DateRangePicker';
-import { SingleInputDateRangePicker } from '@mui/x-date-pickers-pro/SingleInputDateRangePicker';
 <DateRangePicker
-  slots={{ field: SingleInputDateRangePicker }}
 />
⏩ Month Calendar
To simplify the theme and class structure, the <PickersMonth /> component has been moved inside the Month Calendar component.
This change causes a few breaking changes:
- The classes from - pickersMonthClasseshave been moved inside- monthCalendarClasses:- -import { pickersMonthClasses } from '@mui/x-date-pickers/MonthCalendar'; +import { monthCalendarClasses } from '@mui/x-date-pickers/MonthCalendar'; -const buttonClassName = pickersMonthClasses.monthButton; +const buttonClassName = monthCalendarClasses.button; -const selectedButtonClassName = pickersMonthClasses.selected; +const selectedButtonClassName = monthCalendarClasses.selected; -const disabledButtonClassName = pickersMonthClasses.disabled; +const disabledButtonClassName = monthCalendarClasses.disabled;
- The - monthButtonslot of the- PickersMonthstyle overrides has been replaced by the- buttonslot of the- MonthCalendartheme entry:- const theme = createTheme({ components: { - MuiPickersMonth: { + MuiMonthCalendar: { styleOverrides: { - monthButton: { + button: { color: 'red', }, }, }, }, });
- The button to render a single month is no longer wrapped in a - <div />, the spacing are instead defined inside the- rootslot of the Month Calendar.
⏩ Year Calendar
To simplify the theme and class structure, the <PickersYear /> component has been moved inside the Year Calendar component.
This change causes a few breaking changes:
- The classes from - pickersYearClasseshave been moved inside- yearCalendarClasses:- -import { pickersYearClasses } from '@mui/x-date-pickers/YearCalendar'; +import { yearCalendarClasses } from '@mui/x-date-pickers/YearCalendar'; -const buttonClassName = pickersYearClasses.monthButton; +const buttonClassName = yearCalendarClasses.button; -const selectedButtonClassName = pickersYearClasses.selected; +const selectedButtonClassName = yearCalendarClasses.selected; -const disabledButtonClassName = pickersYearClasses.disabled; +const disabledButtonClassName = yearCalendarClasses.disabled;
- The - yearButtonslot of the- PickersYearstyle overrides has been replaced by the- buttonslot of the- YearCalendartheme entry:- const theme = createTheme({ components: { - MuiPickersYear: { + MuiYearCalendar: { styleOverrides: { - yearButton: { + button: { color: 'red', }, }, }, }, });
- The button to render a single year is no longer wrapped in a - <div />, the spacing are instead defined inside the- rootslot of the Year Calendar.
⏩ Treat partially filled date as null in onChange
Before version v8.x, entering a partially filled date in the field would fire onChange with an invalid date.
The date now remains null until fully filled.
Here are two concrete examples:
A user fills a Date Field that has no default value
- The user enters the month, the rendered value is 01/DD/YYYY,onChangeis not fired.
- The user enters the day, the rendered value is 01/01/YYYY,onChangeis not fired.
- The user enters the year, the rendered value is 01/01/2025,onChangeis fired with the new date.
A user cleans the year of a Date Field and enters a new year
- The user cleans the year, the rendered value is 01/01/YYYY,onChangeis fired withnull.
- The user enters a new year, the rendered value is 01/01/2026,onChangeis fired with the new date.
⏩ Deprecate the disableOpenPicker prop
The disableOpenPicker prop has been deprecated on all Picker components and will be removed in the next major release (v9.0.0).
If you only want to allow editing through the field, you can use the field component directly:
-<DatePicker disableOpenPicker />
+<DateField />
-<TimePicker disableOpenPicker />
+<TimeField />
-<DateTimePicker disableOpenPicker />
+<DateTimeField />
-<DateRangePicker disableOpenPicker>
+<SingleInputDateRangeField> // If you want a single input for both dates.
+<MultiInputDateRangeField> // If you want one input for each date.
-<TimeRangePicker disableOpenPicker>
+<SingleInputTimeRangeField> // If you want a single input for both dates.
+<MultiInputTimeRangeField> // If you want one input for each date.
-<DateTimeRangePicker disableOpenPicker>
+<SingleInputDateTimeRangeField> // If you want a single input for both dates.
+<MultiInputDateTimeRangeField> // If you want one input for each date.
⏩ Update default closeOnSelect and Action Bar actions values
The default value of the closeOnSelect prop has been updated to false for all Picker components, except <DesktopDatePicker /> and <DesktopDateRangePicker />, which still have closeOnSelect set to true.
This change goes hand in hand with the new default actions prop value for the <PickersActionBar /> component.
The default value of the actions prop has been updated to ['cancel', 'accept'] for all Picker components, except <DesktopDatePicker /> and <DesktopDateRangePicker />.
If the updated values do not fit your use case, you can override them.
Slots breaking changes
Slot: field
- The component passed to the - fieldslot no longer receives- InputPropsand- inputPropsprops. You now need to manually add the UI to open the picker using the- usePickerContexthook:- import { unstable_useDateField } from '@mui/x-date-pickers/DateField'; +import { usePickerContext } from '@mui/x-date-pickers/hooks'; function CustomField(props) { + const pickerContext = usePickerContext(); return ( <TextField {...customProps} - InputProps={props.InputProps} + InputProps={{ + ref: pickerContext.triggerRef, + endAdornment: ( + <InputAdornment position="end"> + <IconButton + onClick={() => pickerContext.setOpen((prev) => !prev)} + edge="end" + aria-label={fieldResponse.openPickerAriaLabel} + > + <CalendarIcon /> + </IconButton> + </InputAdornment> + ), + }} /> ); }- If you are extracting the - reffrom- InputPropsto pass it to another trigger component, you can replace it with- pickerContext.triggerRef:- +import { usePickerContext } from '@mui/x-date-pickers/hooks'; function CustomField(props) { + const pickerContext = usePickerContext(); return ( <button {...customProps} - ref={props.InputProps?.ref} + ref={pickerContext.triggerRef} > Open picker </button> ); }- If you are using a custom editing behavior, instead of using the - openPickerAriaLabelproperty returned by the- useXXXFieldhooks, you can generate it manually:- +import { usePickerTranslations } from '@mui/x-date-pickers/hooks'; function CustomField(props) { + const translations = usePickerTranslations(); + const formattedValue = props.value?.isValid() ? value.format('ll') : null; + const ariaLabel = translations.openDatePickerDialogue(formattedValue); return ( <button {...customProps} - ref={props.InputProps?.ref} + ref={pickerContext.triggerRef} + aria-label={ariaLabel} > Open picker </button> ); }
- The component passed to the - fieldslot no longer receives the- value,- onChange,- timezone,- format,- disabled,- className,- sx,- label,- name,- autoFocus,- focusedand- readOnlyprops. You can use the- usePickerContexthook instead:- +import { usePickerContext } from '@mui/x-date-pickers/hooks'; -const { value } = props; -const { value } = props; +const { value } = usePickerContext(); -const { onChange } = props; -onChange(dayjs(), { validationError: null }); +const { setValue } = usePickerContext(); -setValue(dayjs(), { validationError: null }); -const { timezone } = props; +const { timezone } = usePickerContext(); -const { format } = props; +const { fieldFormat } = usePickerContext(); -const { disabled } = props; +const { disabled } = usePickerContext(); -const { className } = props; +const { rootClassName } = usePickerContext(); -const { sx } = props; +const { rootSx } = usePickerContext(); -const { label } = props; +const { label } = usePickerContext(); -const { name } = props; +const { name } = usePickerContext(); -const { autoFocus } = props; +const { autoFocus: pickerAutoFocus, open } = usePickerContext(); +const autoFocus = pickerAutoFocus && !open, -const { focused } = props; +const { open } = usePickerContext(); +const focused = open ? true : undefined; -const { readOnly } = props; +const { readOnly } = usePickerContext();
- The component passed to the - fieldslot no longer receives a- ref. You can use the- usePickerContexthook instead:- +import { usePickerContext } from '@mui/x-date-pickers/hooks'; -const CustomField = React.forwardRef(function CustomField(props, ref) { - return <input ref={ref} />; -}); +function CustomField(props) { + const { rootRef } = usePickerContext(); + return <input ref={rootRef} />; +}
- The component passed to the - fieldslot no longer receives the- formatDensity,- enableAccessibleFieldDOMStructure,- selectedSections,- onSelectedSectionsChangeand- inputRefprops. These props, formerly mirroring the picker's props, are no longer exposed. You can manually pass them using- slotProps.fieldto keep the same behavior:- <DatePicker enableAccessibleFieldDOMStructure={false} formatDensity='spacious' selectedSections={selectedSections} onSelectedSectionsChange={onSelectedSectionsChange} inputRef={inputRef} + slotProps={{ field: { enableAccessibleFieldDOMStructure: false, formatDensity: 'spacious', selectedSections, onSelectedSectionsChange, inputRef, }, }} />- If you were not passing those props to the picker, then you can use their default values: - formatDensity:- "dense"
- enableAccessibleFieldDOMStructure:- true
- selectedSections:- undefined
- onSelectedSectionsChange:- undefined
- inputRef:- undefined
 
Slot: inputAdornment
- The - positionprops passed to the- inputAdornmentslot props no longer sets the position of the opening button. This allows defining the position of the opening and clear buttons independently. You can use the- openPickerButtonPositionprop instead:- <DatePicker slotProps={{ - inputAdornment: { position: 'start' }, + field: { openPickerButtonPosition: 'start' }, }} />
⏩ Slot: layout
- The - <PickersLayoutRoot />and- <PickersLayoutContentWrapper />components must now receive the- ownerStatereturned by- usePickerLayoutinstead of their props:- -const { toolbar, tabs, content, actionBar } = usePickerLayout(props); +const { toolbar, tabs, content, actionBar, ownerState } = usePickerLayout(props); return ( - <PickersLayoutRoot ownerState={props}> - <PickersLayoutContentWrapper> + <PickersLayoutRoot ownerState={ownerState}> + <PickersLayoutContentWrapper ownerState={ownerState}> </PickersLayoutContentWrapper> </PickersLayoutRoot> );
- The component passed to the - layoutslot no longer receives the- valueprop. You can use the- usePickerContexthook instead:- +import { usePickerContext } from '@mui/x-date-pickers/hooks'; // This contains a small behavior change. // If the picker receives an invalid date, // the old value equals `null`. // the new value equals the invalid date received. -const { value } = props; +const { value } = usePickerContext();
- The component passed to the - layoutslot no longer receives the- disabledand- readOnlyprops. You can use the- usePickerContexthook instead:- +import { usePickerContext } from '@mui/x-date-pickers/hooks'; -const { disabled } = props; +const { disabled } = usePickerContext(); -const { readOnly } = props; +const { readOnly } = usePickerContext();
- The component passed to the - layoutslot no longer receives the- isRtlprop. You can use the- useRtlhook from- @mui/systeminstead:- +import { useRtl } from '@mui/system/RtlProvider'; - const { isRtl } = props; + const isRtl = useRtl();
- The component passed to the - layoutslot no longer receives the- orientationand- isLandscapeprops. You can use the- usePickerContexthook instead:- +import { usePickerContext } from '@mui/x-date-pickers/hooks'; -const { orientation } = props; +const { orientation } = usePickerContext(); -const { isLandscape } = props; +const { orientation } = usePickerContext(); +const isLandscape = orientation === 'landscape';
- The component passed to the - layoutslot no longer receives the- wrapperVariantprop. You can use the- usePickerContexthook instead:- +import { usePickerContext } from '@mui/x-date-pickers/hooks'; -const { wrapperVariant } = props; +const { variant } = usePickerContext();
- The component passed to the - layoutslot no longer receives the- view,- viewsand- onViewChangeprops. You can use the- usePickerContexthook instead:- +import { usePickerContext } from '@mui/x-date-pickers/hooks'; -const { view } = props; +const { view } = usePickerContext(); -const { views } = props; +const { views } = usePickerContext(); -const { onViewChange } = props; -onViewChange('month'); +const { setView } = usePickerContext(); +setView('month');
- The component passed to the - layoutslot no longer receives the- onClear,- onSetToday,- onAccept,- onCancel,- onOpen,- onClose- onDismiss,- onChangeand- onSelectShortcutprops. You can use the- usePickerActionsContextor the- usePickerContexthooks instead:- +import { usePickerActionsContext } from '@mui/x-date-pickers/hooks'; -const { onClear } = props; +const { clearValue } = usePickerActionsContext(); -const { onSetToday } = props; +const { setValueToToday } = usePickerActionsContext(); -const { onAccept } = props; +const { acceptValueChanges } = usePickerActionsContext(); -const { onCancel } = props; +const { cancelValueChanges } = usePickerActionsContext(); -const { onOpen } = props; +const { setOpen } = usePickerActionsContext(); +const onOpen = event => { + event.preventDefault(); + setOpen(true); +} -const { onClose } = props; +const { setOpen } = usePickerActionsContext(); +const onClose = event => { + event.preventDefault(); + setOpen(false); +} // This contains a small behavior change. // If the picker is not controlled and has a default value, // opening it and calling `acceptValueChanges` without any change calls `onAccept` // with the default value. // Whereas before, opening it and calling `onDimiss` without any change // did not call `onAccept`. -const { onDismiss } = props; +const { acceptValueChanges } = usePickerActionsContext(); +const onDismiss = acceptValueChanges -const { onChange } = props; -onChange(dayjs(), 'partial'); -onChange(dayjs(), 'finish'); +const { setValue } = usePickerActionsContext(); +setValue(dayjs(), { changeImportance: 'set' }); +setValue(dayjs(), { changeImportance: 'accept' }); -const { onSelectShortcut } = props; -onSelectShortcut(dayjs(), 'accept', myShortcut); +const { setValue } = usePickerActionsContext(); +setValue(dayjs(), { changeImportance: 'accept', shortcut: myShortcut });
- The component passed to the - layoutslot no longer receives the- rangePositionand- onRangePositionChangeon range pickers. You can use the- usePickerRangePositionContexthook instead:- +import { usePickerRangePositionContext } from '@mui/x-date-pickers-pro/hooks'; -const { rangePosition } = props; +const { rangePosition } = usePickerRangePositionContext(); -const { onRangePositionChange } = props; -onRangePositionChange('start'); +const { setRangePosition } = usePickerRangePositionContext(); +setRangePosition('start');
⏩ Slot: toolbar
- The component passed to the - toolbarslot no longer receives the- valueprop. You can use the- usePickerContexthook instead:- +import { usePickerContext } from '@mui/x-date-pickers/hooks'; // This contains a small behavior change. // If the picker receives an invalid date, // the old value would equal `null`. // the new value would equal the invalid date received. -const { value } = props; +const { value } = usePickerContext();
- The component passed to the - toolbarslot no longer receives the- disabledand- readOnlyprops. You can use the- usePickerContexthook instead:- +import { usePickerContext } from '@mui/x-date-pickers/hooks'; -const { disabled } = props; +const { disabled } = usePickerContext(); -const { readOnly } = props; +const { readOnly } = usePickerContext();
- The component passed to the - toolbarslot no longer receives the- isLandscapeprop. You can use the- usePickerContexthook instead:- +import { usePickerContext } from '@mui/x-date-pickers/hooks'; -const { isLandscape } = props; +const { orientation } = usePickerContext(); +const isLandscape = orientation === 'landscape';
- The component passed to the - toolbarslot no longer receives the- view,- viewsand- onViewChangeprops. You can use the- usePickerContexthook instead:- +import { usePickerContext } from '@mui/x-date-pickers/hooks'; -const { view } = props; +const { view } = usePickerContext(); -const { views } = props; +const { views } = usePickerContext(); -const { onViewChange } = props; +const { onViewChange } = usePickerContext();
- The component passed to the - toolbarslot no longer receives the- onChangeprop. You can use the- usePickerActionsContextor the- usePickerContexthooks instead:- +import { usePickerActionsContext } from '@mui/x-date-pickers/hooks'; -const { onChange } = props; -onChange(dayjs(), 'partial'); -onChange(dayjs(), 'finish'); +const { setValue } = usePickerActionsContext(); +setValue(dayjs(), { changeImportance: 'set' }); +setValue(dayjs(), { changeImportance: 'accept' });
- The component passed to the - toolbarslot no longer receives the- rangePositionand- onRangePositionChangeon range pickers, instead you can use the- usePickerRangePositionContexthook:- +import { usePickerRangePositionContext } from '@mui/x-date-pickers-pro/hooks'; -const { rangePosition } = props; +const { rangePosition } = usePickerRangePositionContext(); -const { onRangePositionChange } = props; -onRangePositionChange('start'); +const { setRangePosition } = usePickerRangePositionContext(); +setRangePosition('start');
⏩ Slot: tabs
- The component passed to the - tabsslot no longer receives the- view,- viewsand- onViewChangeprops. You can use the- usePickerContexthook instead:- +import { usePickerContext } from '@mui/x-date-pickers/hooks'; -const { view } = props; +const { view } = usePickerContext(); -const { views } = props; +const { views } = usePickerContext(); -const { onViewChange } = props; +const { onViewChange } = usePickerContext();
- The component passed to the - tabsslot no longer receives the- rangePositionand- onRangePositionChangeon range pickers, instead you can use the- usePickerRangePositionContexthook:- +import { usePickerRangePositionContext } from '@mui/x-date-pickers-pro/hooks'; -const { rangePosition } = props; +const { rangePosition } = usePickerRangePositionContext(); -const { onRangePositionChange } = props; -onRangePositionChange('start'); +const { setRangePosition } = usePickerRangePositionContext(); +setRangePosition('start');
⏩ Slot: actionBar
- The component passed to the - actionBarslot no longer receives the- onClear,- onSetToday,- onAcceptand- onCancelprops. You can use the- usePickerActionsContextor the- usePickerContexthooks instead:- +import { usePickerActionsContext } from '@mui/x-date-pickers/hooks'; -const { onClear } = props; +const { clearValue } = usePickerActionsContext(); -const { onSetToday } = props; +const { setValueToToday } = usePickerActionsContext(); -const { onAccept } = props; +const { acceptValueChanges } = usePickerActionsContext(); -const { onCancel } = props; +const { cancelValueChanges } = usePickerActionsContext();
⏩ Slot: shortcuts
- The component passed to the - shortcutsslot no longer receives the- isLandscapeprop. You can use the- usePickerContexthook instead:- +import { usePickerContext } from '@mui/x-date-pickers/hooks'; -const { isLandscape } = props; +const { orientation } = usePickerContext(); +const isLandscape = orientation === 'landscape';
- The component passed to the - shortcutsslot no longer receives the- onChangeprop. You can use the- usePickerActionsContextor the- usePickerContexthooks instead:- -const { onChange } = props; -onChange(dayjs(), 'accept', myShortcut); +const { setValue } = usePickerActionsContext(); +setValue(dayjs(), { changeImportance: 'accept', shortcut: myShortcut });
- The component passed to the - shortcutsslot no longer receives the- isValidprop. You can use the- useIsValidValuehook instead:- +import { useIsValidValue } from '@mui/x-date-pickers/hooks'; -const { isValid } = props; -const isTodayValid = isValid(dayjs()); +const isValidValue = useIsValidValue(); +const isTodayValid = isValidValue(dayjs());
✅ Renamed variables and types
The following variables and types have been renamed to have a coherent Picker / Pickers prefix:
- ✅ - usePickersTranslations- -import { usePickersTranslations } from '@mui/x-date-pickers/hooks'; -import { usePickersTranslations } from '@mui/x-date-pickers'; -import { usePickersTranslations } from '@mui/x-date-pickers-pro'; +import { usePickerTranslations } from '@mui/x-date-pickers/hooks'; +import { usePickerTranslations } from '@mui/x-date-pickers'; +import { usePickerTranslations } from '@mui/x-date-pickers-pro'; -const translations = usePickersTranslations(); +const translations = usePickerTranslations();
- ✅ - usePickersContext- -import { usePickersContext } from '@mui/x-date-pickers/hooks'; -import { usePickersContext } from '@mui/x-date-pickers'; -import { usePickersContext } from '@mui/x-date-pickers-pro'; +import { usePickerContext } from '@mui/x-date-pickers/hooks'; +import { usePickerContext } from '@mui/x-date-pickers'; +import { usePickerContext } from '@mui/x-date-pickers-pro'; -const pickersContext = usePickersContext(); +const pickerContext = usePickerContext();
- ✅ - FieldValueType- -import { FieldValueType } from '@mui/x-date-pickers/models'; -import { FieldValueType } from '@mui/x-date-pickers'; -import { FieldValueType } from '@mui/x-date-pickers-pro'; +import { PickerValueType } from '@mui/x-date-pickers/models'; +import { PickerValueType } from '@mui/x-date-pickers'; +import { PickerValueType } from '@mui/x-date-pickers-pro';
- ✅ - RangeFieldSection- -import { RangeFieldSection } from '@mui/x-date-pickers-pro/models'; -import { RangeFieldSection } from '@mui/x-date-pickers-pro'; +import { FieldRangeSection } from '@mui/x-date-pickers-pro/models'; +import { FieldRangeSection } from '@mui/x-date-pickers-pro';
- ✅ - PickerShortcutChangeImportance- -import { PickerShortcutChangeImportance } from '@mui/x-date-pickers/PickersShortcuts'; -import { PickerShortcutChangeImportance } from '@mui/x-date-pickers'; -import { PickerShortcutChangeImportance } from '@mui/x-date-pickers-pro'; +import { PickerChangeImportance } from '@mui/x-date-pickers/models'; +import { PickerChangeImportance } from '@mui/x-date-pickers'; +import { PickerChangeImportance } from '@mui/x-date-pickers-pro';
⏩ Hooks breaking changes
⏩ useMultiInputDateRangeField
This hook has been removed in favor of the new useMultiInputRangeField hook with an improved DX:
 import useSlotProps from '@mui/utils/useSlotProps';
-import { unstable_useMultiInputDateRangeField as useMultiInputDateRangeField } from '@mui/x-date-pickers-pro/MultiInputDateRangeField';
+import { useDateRangeManager } from '@mui/x-date-pickers-pro/managers';
+import { unstable_useMultiInputRangeField as useMultiInputRangeField } from '@mui/x-date-pickers-pro/hooks';
 import { useSplitFieldProps } from '@mui/x-date-pickers/hooks';
 const DateRangeField(props) {
   const { internalProps, forwardedProps } = useSplitFieldProps(props, 'date');
   const { slotProps, slots } = forwardedProps;
   const startTextFieldProps = useSlotProps({
     elementType: 'input',
     externalSlotProps: slotProps?.textField,
     ownerState: { ...props, position: 'start' },
   });
   const endTextFieldProps = useSlotProps({
     elementType: 'input',
     externalSlotProps: slotProps?.textField,
     ownerState: { ...props, position: 'end' },
   });
-  const fieldResponse = useMultiInputDateRangeField({
-    sharedProps: internalProps,
-    startTextFieldProps,
-    endTextFieldProps,
-    unstableStartFieldRef: internalProps.unstableStartFieldRef,
-    unstableEndFieldRef: internalProps.unstableEndFieldRef,
-  });
+  const manager = useDateRangeManager(props);
+  const fieldResponse = useMultiInputRangeField({
+    manager,
+    internalProps,
+    startForwardedProps: startTextFieldProps,
+    endForwardedProps: endTextFieldProps,
+  });
   return (/** Your UI */);
 }
⏩ useMultiInputTimeRangeField
This hook has been removed in favor of the new useMultiInputRangeField hook with an improved DX:
 import useSlotProps from '@mui/utils/useSlotProps';
-import { unstable_useMultiInputTimeRangeField as useMultiInputTimeRangeField } from '@mui/x-date-pickers-pro/MultiInputTimeRangeField';
+import { useTimeRangeManager } from '@mui/x-date-pickers-pro/managers';
+import { unstable_useMultiInputRangeField as useMultiInputRangeField } from '@mui/x-date-pickers-pro/hooks';
 import { useSplitFieldProps } from '@mui/x-date-pickers/hooks';
 const DateRangeField(props) {
   const { internalProps, forwardedProps } = useSplitFieldProps(props, 'time');
   const { slotProps, slots } = forwardedProps;
   const startTextFieldProps = useSlotProps({
     elementType: 'input',
     externalSlotProps: slotProps?.textField,
     ownerState: { ...props, position: 'start' },
   });
   const endTextFieldProps = useSlotProps({
     elementType: 'input',
     externalSlotProps: slotProps?.textField,
     ownerState: { ...props, position: 'end' },
   });
-  const fieldResponse = useMultiInputTimeRangeField({
-    sharedProps: internalProps,
-    startTextFieldProps,
-    endTextFieldProps,
-    unstableStartFieldRef: internalProps.unstableStartFieldRef,
-    unstableEndFieldRef: internalProps.unstableEndFieldRef,
-  });
+  const manager = useTimeRangeManager(props);
+  const fieldResponse = useMultiInputRangeField({
+    manager,
+    internalProps,
+    startForwardedProps: startTextFieldProps,
+    endForwardedProps: endTextFieldProps,
+  });
   return (/** Your UI */);
 }
⏩ useMultiInputDateTimeRangeField
This hook has been removed in favor of the new useMultiInputRangeField hook with an improved DX:
 import useSlotProps from '@mui/utils/useSlotProps';
-import { unstable_useMultiInputDateTimeRangeField as useMultiInputDateTimeRangeField } from '@mui/x-date-pickers-pro/MultiInputDateTimeRangeField';
+import { useDateTimeRangeManager } from '@mui/x-date-pickers-pro/managers';
+import { unstable_useMultiInputRangeField as useMultiInputRangeField } from '@mui/x-date-pickers-pro/hooks';
 import { useSplitFieldProps } from '@mui/x-date-pickers/hooks';
 const DateRangeField(props) {
   const { internalProps, forwardedProps } = useSplitFieldProps(props, 'date-time');
   const { slotProps, slots } = forwardedProps;
   const startTextFieldProps = useSlotProps({
     elementType: 'input',
     externalSlotProps: slotProps?.textField,
     ownerState: { ...props, position: 'start' },
   });
   const endTextFieldProps = useSlotProps({
     elementType: 'input',
     externalSlotProps: slotProps?.textField,
     ownerState: { ...props, position: 'end' },
   });
-  const fieldResponse = useMultiInputDateTimeRangeField({
-    sharedProps: internalProps,
-    startTextFieldProps,
-    endTextFieldProps,
-    unstableStartFieldRef: internalProps.unstableStartFieldRef,
-    unstableEndFieldRef: internalProps.unstableEndFieldRef,
-  });
+  const manager = useDateTimeRangeManager(props);
+  const fieldResponse = useMultiInputRangeField({
+    manager,
+    internalProps,
+    startForwardedProps: startTextFieldProps,
+    endForwardedProps: endTextFieldProps,
+  });
   return (/** Your UI */);
 }
⏩ usePickerContext
- The - onOpenand- onClosemethods have been replaced with a single- setOpenmethod. This method no longer takes an event, which was used to prevent the browser default behavior:- const pickerContext = usePickerContext(); -<button onClick={pickerContext.onOpen}>Open</button> +<button onClick={() => pickerContext.setOpen(true)}>Open</button> -<button onClick={pickerContext.onClose}>Close</button> +<button onClick={() => pickerContext.setOpen(false)}>Open</button> -<button - onClick={(event) => - pickerContext.open ? pickerContext.onClose(event) : pickerContext.onOpen(event) - } -> - Toggle -</button> +<button onClick={() => pickerContext.setOpen(prev => !prev)}>Toggle</button>- If you want to prevent the default behavior, you now have to do it manually: - <div onKeyDown={(event) => { if (event.key === 'Escape') { - pickerContext.onClose(); + event.preventDefault(); + pickerContext.setOpen(false); } }} />
⏩ useClearableField
This hook has been removed. The custom field component now receives the clearable and onClear props.
You can remove the useClearableField hook from your component and use the new props to conditionally render the clear button:
-import { useClearableField } from '@mui/x-date-pickers-pro/hooks';
 function CustomField(props) {
   const {
     id,
     label
     value,
+    clearable,
+    onClear,
   } = props;
-  const processedFieldProps = useClearableField({
-    ...fieldResponse,
-    slots,
-    slotProps,
-  });
+  {clearable && value && (
+    <IconButton title="Clear" tabIndex={-1} onClick={onClear}>
+      <ClearIcon />
+    </IconButton>
+  )}
 }
Typing breaking changes
Do not pass the date object as a generic
The TDate generic has been removed from all the types, interfaces, and variables of the @mui/x-date-pickers and @mui/x-date-pickers-pro packages.
If you were passing your date object type as a generic to any element of one of those packages, you can remove it:
-<DatePicker<Dayjs> value={value} onChange={onChange} />
+<DatePicker value={value} onChange={onChange} />
-type FieldComponent = DatePickerSlots<Dayjs>['field'];
+type FieldComponent = DatePickerSlots['field'];
-function CustomDatePicker(props: DatePickerProps<Dayjs>) {}
+function CustomDatePicker(props: DatePickerProps) {}
Do not pass the section type as a generic
The TSection generic of the FieldRef type has been replaced with the TValue generic:
-const fieldRef = React.useRef<FieldRef<FieldSection>>(null);
+const fieldRef = React.useRef<Dayjs | null>(null);
-const fieldRef = React.useRef<FieldRef<RangeFieldSection>>(null);
+const fieldRef = React.useRef<DateRange<Dayjs>>(null);
⏩ Removed types
The following types are no longer exported by @mui/x-date-pickers and/or @mui/x-date-pickers-pro.
- NonEmptyDateRange- // When using AdapterDayjs import { Dayjs } from 'dayjs'; type NonEmptyDateRange = [Dayjs, Dayjs]; // When using AdapterLuxon import { DateTime } from 'luxon'; type NonEmptyDateRange = [DateTime, DateTime]; // When using AdapterMoment, AdapterMomentJalaali or AdapterMomentHijri import { Moment } from 'moment'; type NonEmptyDateRange = [Moment, Moment]; // When using AdapterDateFns, AdapterDateFnsV3, AdapterDateFnsJalali or AdapterDateFnsJalaliV3 type NonEmptyDateRange = [Date, Date];
- UseDateFieldComponentProps- import { UseDateFieldProps } from '@mui/x-date-pickers/DateField'; import { PickerValidDate } from '@mui/x-date-pickers/models'; type UseDateFieldComponentProps< TDate extends PickerValidDate, TEnableAccessibleFieldDOMStructure extends boolean, TChildProps extends {}, > = Omit< TChildProps, keyof UseDateFieldProps<TDate, TEnableAccessibleFieldDOMStructure> > & UseDateFieldProps<TDate, TEnableAccessibleFieldDOMStructure>;
- UseTimeFieldComponentProps- import { UseTimeFieldProps } from '@mui/x-date-pickers/TimeField'; import { PickerValidDate } from '@mui/x-date-pickers/models'; type UseTimeFieldComponentProps< TDate extends PickerValidDate, TEnableAccessibleFieldDOMStructure extends boolean, TChildProps extends {}, > = Omit< TChildProps, keyof UseTimeFieldProps<TDate, TEnableAccessibleFieldDOMStructure> > & UseTimeFieldProps<TDate, TEnableAccessibleFieldDOMStructure>;
- UseDateTimeFieldComponentProps- import { UseDateTimeFieldProps } from '@mui/x-date-pickers/DateTimeField'; import { PickerValidDate } from '@mui/x-date-pickers/models'; type UseDateTimeFieldComponentProps< TDate extends PickerValidDate, TEnableAccessibleFieldDOMStructure extends boolean, TChildProps extends {}, > = Omit< TChildProps, keyof UseDateTimeFieldProps<TDate, TEnableAccessibleFieldDOMStructure> > & UseDateTimeFieldProps<TDate, TEnableAccessibleFieldDOMStructure>;
- UseDateRangeFieldProps- import { DateRangeManagerFieldInternalProps } from '@mui/x-date-pickers-pro/managers'; interface UseDateRangeFieldProps< TEnableAccessibleFieldDOMStructure extends boolean, > extends Omit< DateRangeManagerFieldInternalProps<TEnableAccessibleFieldDOMStructure>, 'unstableFieldRef' > {}
- UseMultiInputDateRangeFieldProps- import { DateRangeManagerFieldInternalProps } from '@mui/x-date-pickers-pro/managers'; import { MultiInputFieldRefs } from '@mui/x-date-pickers-pro/models'; interface UseMultiInputDateRangeFieldProps< TEnableAccessibleFieldDOMStructure extends boolean, > extends DateRangeManagerFieldInternalProps<TEnableAccessibleFieldDOMStructure>, MultiInputFieldRefs {}
- UseMultiInputDateRangeFieldComponentProps- import { DateRangeManagerFieldInternalProps } from '@mui/x-date-pickers-pro/managers'; import { MultiInputFieldRefs } from '@mui/x-date-pickers-pro/models'; type UseMultiInputDateRangeFieldComponentProps< TEnableAccessibleFieldDOMStructure extends boolean, TChildProps extends {}, > = Omit< TChildProps, | keyof DateRangeManagerFieldInternalProps<TEnableAccessibleFieldDOMStructure> | keyof MultiInputFieldRefs > & DateRangeManagerFieldInternalProps<TEnableAccessibleFieldDOMStructure> & MultiInputFieldRefs;
- UseMultiInputTimeRangeFieldProps- import { TimeRangeManagerFieldInternalProps } from '@mui/x-date-pickers-pro/managers'; import { MultiInputFieldRefs } from '@mui/x-date-pickers-pro/models'; interface UseMultiInputTimeRangeFieldProps< TEnableAccessibleFieldDOMStructure extends boolean, > extends TimeRangeManagerFieldInternalProps<TEnableAccessibleFieldDOMStructure>, MultiInputFieldRefs {}
- UseMultiInputTimeRangeFieldComponentProps- import { TimeRangeManagerFieldInternalProps } from '@mui/x-date-pickers-pro/managers'; import { MultiInputFieldRefs } from '@mui/x-date-pickers-pro/models'; type UseMultiInputTimeRangeFieldComponentProps< TEnableAccessibleFieldDOMStructure extends boolean, TChildProps extends {}, > = Omit< TChildProps, | keyof TimeRangeManagerFieldInternalProps<TEnableAccessibleFieldDOMStructure> | keyof MultiInputFieldRefs > & TimeRangeManagerFieldInternalProps<TEnableAccessibleFieldDOMStructure> & MultiInputFieldRefs;
- UseMultiInputDateTimeRangeFieldProps- import { DateTimeRangeManagerFieldInternalProps } from '@mui/x-date-pickers-pro/managers'; import { MultiInputFieldRefs } from '@mui/x-date-pickers-pro/models'; interface UseMultiInputDateTimeRangeFieldProps< TEnableAccessibleFieldDOMStructure extends boolean, > extends DateTimeRangeManagerFieldInternalProps<TEnableAccessibleFieldDOMStructure>, MultiInputFieldRefs {}
- UseMultiInputDateTimeRangeFieldComponentProps- import { DateTimeRangeManagerFieldInternalProps } from '@mui/x-date-pickers-pro/managers'; import { MultiInputFieldRefs } from '@mui/x-date-pickers-pro/models'; type UseMultiInputDateTimeRangeFieldComponentProps< TEnableAccessibleFieldDOMStructure extends boolean, TChildProps extends {}, > = Omit< TChildProps, | keyof DateTimeRangeManagerFieldInternalProps<TEnableAccessibleFieldDOMStructure> | keyof MultiInputFieldRefs > & DateTimeRangeManagerFieldInternalProps<TEnableAccessibleFieldDOMStructure> & MultiInputFieldRefs;
- MultiInputRangeFieldClasses- // If you were using MultiInputRangeFieldClasses for a date range field. import { MultiInputDateRangeFieldClasses } from '@mui/x-date-pickers-pro/MultiInputDateRangeField'; // If you were using MultiInputRangeFieldClasses for a time range field. import { MultiInputTimeRangeFieldClasses } from '@mui/x-date-pickers-pro/MultiInputTimeRangeField'; // If you were using MultiInputRangeFieldClasses for a date time range field. import { MultiInputDateTimeRangeFieldClasses } from '@mui/x-date-pickers-pro/MultiInputDateTimeRangeField';
- MultiInputRangeFieldClassKey- // If you were using MultiInputRangeFieldClassKey for a date range field. import { MultiInputRangeFieldClassKey } from '@mui/x-date-pickers-pro/MultiInputDateRangeField'; // If you were using MultiInputRangeFieldClassKey for a time range field. import { MultiInputRangeFieldClassKey } from '@mui/x-date-pickers-pro/MultiInputTimeRangeField'; // If you were using MultiInputRangeFieldClassKey for a date time range field. import { MultiInputRangeFieldClassKey } from '@mui/x-date-pickers-pro/MultiInputDateTimeRangeField';
- BaseSingleInputFieldProps- If you are building a custom field for a Date Picker: - -import { - BaseSingleInputFieldProps, - DateValidationError, - FieldSection, -} from '@mui/x-date-pickers/models'; -import { UseDateFieldProps } from '@mui/x-date-pickers/DateField'; +import { DatePickerFieldProps } from '@mui/x-date-pickers/DatePicker'; -interface CustomDateFieldProps - extends UseDateFieldProps<Dayjs, true>, - BaseSingleInputFieldProps< - Dayjs | null, - Dayjs, - FieldSection, - true, - DateValidationError - > {} +interface CustomDateFieldProps extends DatePickerFieldProps {}
- If you are building a custom field for a Time Picker: - -import { - BaseSingleInputFieldProps, - TimeValidationError, - FieldSection, -} from '@mui/x-date-pickers/models'; -import { UseTimeFieldProps } from '@mui/x-date-pickers/TimeField'; +import { TimePickerFieldProps } from '@mui/x-date-pickers/TimePicker'; -interface CustomTimeFieldProps - extends UseTimeFieldProps<Dayjs, true>, - BaseSingleInputFieldProps< - Dayjs | null, - Dayjs, - FieldSection, - true, - TimeValidationError - > {} +interface CustomTimeFieldProps extends TimePickerFieldProps {}
- If you are building a custom field for a Date Time Picker: - -import { - BaseSingleInputFieldProps, - DateTimeValidationError, - FieldSection, -} from '@mui/x-date-pickers/models'; -import { UseDateTimeFieldProps } from '@mui/x-date-pickers/DateTimeField'; +import { DateTimePickerFieldProps } from '@mui/x-date-pickers/DateTimePicker'; -interface CustomDateTimeFieldProps - extends UseDateTimeFieldProps<Dayjs, true>, - BaseSingleInputFieldProps< - Dayjs | null, - Dayjs, - FieldSection, - true, - DateTimeValidationError - > {} +interface CustomDateTimeFieldProps extends DateTimePickerFieldProps {}
- If you are building a custom single input field for a Date Range Picker: - -import { - DateRangeValidationError, - RangeFieldSection, - DateRange, -} from '@mui/x-date-pickers-pro/models'; -import { - UseSingleInputDateRangeFieldProps -} from '@mui/x-date-pickers-pro/SingleInputDateRangeField'; +import { DateRangePickerFieldProps } from '@mui/x-date-pickers-pro/DateRangePicker'; -interface CustomDateRangeFieldProps - extends UseSingleInputDateRangeFieldProps<Dayjs, true>, - BaseSingleInputFieldProps< - DateRange<Dayjs>, - Dayjs, - RangeFieldSection, - true, - DateRangeValidationError - > +interface CustomDateRangeFieldProps extends DateRangePickerFieldProps {}
- If you are building a custom single input field for a Date Time Range Picker: - -import { - DateTimeRangeValidationError, - RangeFieldSection, - DateRange, -} from '@mui/x-date-pickers-pro/models'; -import { - UseSingleInputDateTimeRangeFieldProps -} from '@mui/x-date-pickers-pro/SingleInputDateTimeRangeField'; +import { + DateTimeRangePickerFieldProps +} from '@mui/x-date-pickers-pro/DateTimeRangePicker'; -interface CustomDateTimeRangeFieldProps - extends UseSingleInputDateTimeRangeFieldProps<Dayjs, true>, - BaseSingleInputFieldProps< - DateRange<Dayjs>, - Dayjs, - RangeFieldSection, - true, - DateTimeRangeValidationError - > +interface CustomDateTimeRangeFieldProps extends DateTimeRangePickerFieldProps {}
 
- BaseMultiInputFieldProps- If you are building a custom multi input field for a Date Range Picker: - -import { - DateRangeValidationError, - RangeFieldSection, - DateRange, -} from '@mui/x-date-pickers-pro/models'; -import { - UseMultiInputDateRangeFieldProps -} from '@mui/x-date-pickers-pro/MultiInputDateRangeField'; +import { DateRangePickerFieldProps } from '@mui/x-date-pickers-pro/DateRangePicker'; -interface CustomDateRangeFieldProps - extends UseMultiInputDateRangeFieldProps<Dayjs, true>, - BaseMultiInputFieldProps< - DateRange<Dayjs>, - Dayjs, - RangeFieldSection, - true, - DateRangeValidationError - > {} +interface CustomDateRangeFieldProps + extends Omit< + DateRangePickerFieldProps, + 'unstableFieldRef' | 'clearable' | 'onClear' + >, + MultiInputFieldRefs {}
- If you are building a custom multi input field for a Date Time Range Picker: - -import { - DateTimeRangeValidationError, - RangeFieldSection, - DateRange, -} from '@mui/x-date-pickers-pro/models'; -import { - UseMultiInputDateTimeRangeFieldProps -} from '@mui/x-date-pickers-pro/MultiInputDateTimeRangeField'; +import { + DateTimeRangePickerFieldProps +} from '@mui/x-date-pickers-pro/DateTimeRangePicker'; -interface CustomDateTimeRangeFieldProps - extends UseMultiInputDateTimeRangeFieldProps<Dayjs, false>, - BaseMultiInputFieldProps< - DateRange<Dayjs>, - Dayjs, - RangeFieldSection, - false, - DateTimeRangeValidationError - > {} +interface JoyMultiInputDateRangeFieldProps + extends Omit< + DateTimeRangePickerFieldProps, + 'unstableFieldRef' | 'clearable' | 'onClear' + >, + MultiInputFieldRefs {}
 
- BasePickersTextFieldProps- If your Text Field is used inside a non-range picker or in a range-picker with a single input field: - -import { BasePickersTextFieldProps } from '@mui/x-date-pickers-pro/models'; +import { BaseSingleInputPickersTextFieldProps } from '@mui/x-date-pickers/models'; interface CustomTextFieldProps - extends BasePickersTextFieldProps<true> {} + extends BaseSingleInputPickersTextFieldProps<true> {}
- If your Text Field is used inside a range-picker with a multi input field: - -import { BasePickersTextFieldProps } from '@mui/x-date-pickers-pro/models'; +import { BaseMultiInputPickersTextFieldProps } from '@mui/x-date-pickers-pro/models'; interface CustomTextFieldProps - extends BasePickersTextFieldProps<true> {} + extends BaseMultiInputPickersTextFieldProps<true> {}
 
- ExportedUseClearableFieldProps- interface ExportedUseClearableFieldProps { clearable?: boolean; onClear?: React.MouseEventHandler; }
- UseClearableFieldSlots- interface UseClearableFieldSlots { clearIcon?: React.ElementType; clearButton?: React.ElementType; }
- UseClearableFieldSlotProps- import { SlotComponentProps } from '@mui/utils'; import { FieldOwnerState } from '@mui/x-date-pickers/models'; import { ClearIcon } from '@mui/x-date-pickers/icons'; import IconButton from '@mui/material/IconButton'; interface UseClearableFieldSlotProps { clearIcon?: SlotComponentProps<typeof ClearIcon, {}, FieldOwnerState>; clearButton?: SlotComponentProps<typeof IconButton, {}, FieldOwnerState>; }
- UseClearableFieldResponse- type UseClearableFieldResponse<TFieldProps extends {}> = Omit< TFieldProps, 'clearable' | 'onClear' | 'slots' | 'slotProps' >;
Theme breaking change
⏩ MuiPickersPopper
The theme entry have been renamed to have a coherent Picker / Pickers prefix:
 const theme = createTheme({
   components: {
-    MuiPickersPopper: {
+    MuiPickerPopper: {
       styleOverrides: {},
     },
   },
 });
The props that can be overridden have also been limited to the one that did not cause any bugs:
const theme = createTheme({
  components: {
    MuiPickerPopper: {
      defaultProps: {
        // Those are now the props with support for theme default props
        position: "bottom"
        classes: { root: "custom-root-class}
      },
    },
  },
});
⏩ Stop using LicenseInfo from @mui/x-date-pickers-pro
The LicenseInfo object is no longer exported from the @mui/x-date-pickers-pro package.
You can import it from @mui/x-license instead:
-import { LicenseInfo } from '@mui/x-date-pickers-pro';
+import { LicenseInfo } from '@mui/x-license';
 LicenseInfo.setLicenseKey('YOUR_LICENSE_KEY');
⏩ Stop passing utils and the date object to some translation keys
Some translation keys no longer require utils and the date object as parameters, but only the formatted value as a string. The keys affected by this changes are: clockLabelText, openDatePickerDialogue and openTimePickerDialogue.
If you have customized those translation keys, you have to update them following the examples below:
- If you are setting a custom value in a picker component:
-clockLabelText: (view, time, utils) =>
-   `Select ${view}. ${
-     time === null || !utils.isValid(time)
-       ? 'No time selected'
-       : `Selected time is ${utils.format(time, 'fullTime')}`
-   }`
+clockLabelText: (view, formattedTime) =>
+   `Select ${view}. ${
+     formattedTime == null ? 'No time selected' : `Selected time is ${formattedTime}`
+   }`
-openDatePickerDialogue: (value, utils) =>
-  value !== null && utils.isValid(value)
-    ? `Choose date, selected date is ${utils.format(value, 'fullDate')}`
-    : 'Choose date',
+openDatePickerDialogue: (formattedDate) =>
+  formattedDate ? `Choose date, selected date is ${formattedDate}` : 'Choose date'
-openTimePickerDialogue: (value, utils) =>
-  value !== null && utils.isValid(value)
-    ? `Choose time, selected time is ${utils.format(value, 'fullTime')}`
-    : 'Choose time',
+openTimePickerDialogue: (formattedTime) =>
+  formattedTime ? `Choose time, selected time is ${formattedTime}` : 'Choose time'
- If you are setting a custom value in the LocalizationProvider:
 <LocalizationProvider localeText={{
-   clockLabelText: (view, time, utils) =>
-     `Select ${view}. ${
-       time === null || !utils.isValid(time)
-         ? 'No time selected'
-         : `Selected time is ${utils.format(time, 'fullTime')}`
-     }`
+   clockLabelText: (view, formattedTime) =>
+     `Select ${view}. ${
+       formattedTime == null ? 'No time selected' : `Selected time is ${formattedTime}`
+     }`
-   openDatePickerDialogue: (value, utils) =>
-     value !== null && utils.isValid(value)
-      ? `Choose date, selected date is ${utils.format(value, 'fullDate')}`
-      : 'Choose date',
+   openDatePickerDialogue: (formattedDate) =>
+     formattedDate ? `Choose date, selected date is ${formattedDate}` : 'Choose date'
-   openTimePickerDialogue: (value, utils) =>
-     value !== null && utils.isValid(value)
-       ? `Choose time, selected time is ${utils.format(value, 'fullTime')}`
-       : 'Choose time',
+   openTimePickerDialogue: (formattedTime) =>
+     formattedTime ? `Choose time, selected time is ${formattedTime}` : 'Choose time'
 }} >
- If you using this translation key in a custom component:
 const translations = usePickerTranslations();
-const clockLabelText = translations.clockLabelText(
-  view,
-  value,
-  {} as any,
-  value == null ? null : value.format('hh:mm:ss')
-);
+const clockLabelText = translations.clockLabelText(
+  view,
+  value == null ? null : value.format('hh:mm:ss')
+);
-const openDatePickerDialogue = translations.openDatePickerDialogue(
-  value,
-  {} as any,
-  value == null ? null : value.format('MM/DD/YYY')
-);
+const openDatePickerDialogue = translations.openDatePickerDialogue(
+  value == null ? null : value.format('MM/DD/YYY')
+);
-const openTimePickerDialogue = translations.openTimePickerDialogue(
-  value,
-  {} as any,
-  value == null ? null : value.format('hh:mm:ss')
-);
+const openTimePickerDialogue = translations.openTimePickerDialogue(
+  value == null ? null : value.format('hh:mm:ss')
+);
⏩ Remove unused adapter formats
The following unused formats have been removed from the adapters and can no longer be overridden via the dateFormats prop on the <LocalizationProvider /> component:
- fullTime- please use- fullTime12hand- fullTime24hinstead:- <LocalizationProvider dateFormats={{ - fullTime: 'LT', + fullTime12h: 'hh:mm A', + fullTime24h: 'hh:mm', }} >
- keyboardDateTime- please use- keyboardDateTime12hand- keyboardDateTime24hinstead:- <LocalizationProvider dateFormats={{ - keyboardDateTime: 'DD.MM.YYYY | LT', + keyboardDateTime12h: 'DD.MM.YYYY | hh:mm A', + keyboardDateTime24h: 'DD.MM.YYYY | hh:mm', }} >