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
AdapterDateFnsandAdapterDateFnsJalaliadapters have been renamed toAdapterDateFnsV2andAdapterDateFnsJalaliV2respectively. 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-fnsordate-fns-jalalipackage to the latest version and use the updated adapters.The
AdapterDateFnsV3andAdapterDateFnsJalaliV3adapters have been renamed toAdapterDateFnsandAdapterDateFnsJalalirespectively. 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 theactionBarslot handled byDatePicker, byDesktopDatePickeror byPickerLayout?).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 theownerStateof theactionBardidn't contain this information.The naming of the props made it difficult to understand which element they applied to. If the
ownerStateof themonthButtonslot containeddisabled, it was hard to establish whether the disabled state applied to themonthButtonor 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 { MultiInputDateRangeField } from '@mui/x-date-pickers-pro/MultiInputDateRangeField';
<DateRangePicker
+ slots={{ field: MultiInputDateRangeField }}
/>
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 { SingleInputDateRangeField } from '@mui/x-date-pickers-pro/SingleInputDateRangeField';
<DateRangePicker
- slots={{ field: SingleInputDateRangeField }}
/>
⏩ 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 insidemonthCalendarClasses:-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 thePickersMonthstyle overrides has been replaced by thebuttonslot of theMonthCalendartheme 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 therootslot 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 insideyearCalendarClasses:-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 thePickersYearstyle overrides has been replaced by thebuttonslot of theYearCalendartheme 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 therootslot 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 receivesInputPropsandinputPropsprops. You now need to manually add the UI to open the picker using theusePickerContexthook: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
reffromInputPropsto pass it to another trigger component, you can replace it withpickerContext.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 theuseXXXFieldhooks, 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 thevalue,onChange,timezone,format,disabled,className,sx,label,name,autoFocus,focusedandreadOnlyprops. You can use theusePickerContexthook 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 aref. You can use theusePickerContexthook 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 theformatDensity,enableAccessibleFieldDOMStructure,selectedSections,onSelectedSectionsChangeandinputRefprops. These props, formerly mirroring the picker's props, are no longer exposed. You can manually pass them usingslotProps.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:trueselectedSections:undefinedonSelectedSectionsChange:undefinedinputRef:undefined
Slot: inputAdornment
The
positionprops passed to theinputAdornmentslot 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 theopenPickerButtonPositionprop instead:<DatePicker slotProps={{ - inputAdornment: { position: 'start' }, + field: { openPickerButtonPosition: 'start' }, }} />
⏩ Slot: layout
The
<PickersLayoutRoot />and<PickersLayoutContentWrapper />components must now receive theownerStatereturned byusePickerLayoutinstead 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 thevalueprop. You can use theusePickerContexthook 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 thedisabledandreadOnlyprops. You can use theusePickerContexthook 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 theisRtlprop. You can use theuseRtlhook from@mui/systeminstead:+import { useRtl } from '@mui/system/RtlProvider'; - const { isRtl } = props; + const isRtl = useRtl();The component passed to the
layoutslot no longer receives theorientationandisLandscapeprops. You can use theusePickerContexthook 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 thewrapperVariantprop. You can use theusePickerContexthook instead:+import { usePickerContext } from '@mui/x-date-pickers/hooks'; -const { wrapperVariant } = props; +const { variant } = usePickerContext();The component passed to the
layoutslot no longer receives theview,viewsandonViewChangeprops. You can use theusePickerContexthook 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 theonClear,onSetToday,onAccept,onCancel,onOpen,onCloseonDismiss,onChangeandonSelectShortcutprops. You can use theusePickerActionsContextor theusePickerContexthooks 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 therangePositionandonRangePositionChangeon range pickers. You can use theusePickerRangePositionContexthook 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 thevalueprop. You can use theusePickerContexthook 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 thedisabledandreadOnlyprops. You can use theusePickerContexthook 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 theisLandscapeprop. You can use theusePickerContexthook 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 theview,viewsandonViewChangeprops. You can use theusePickerContexthook 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 theonChangeprop. You can use theusePickerActionsContextor theusePickerContexthooks 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 therangePositionandonRangePositionChangeon range pickers, instead you can use theusePickerRangePositionContexthook:+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 theview,viewsandonViewChangeprops. You can use theusePickerContexthook 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 therangePositionandonRangePositionChangeon range pickers, instead you can use theusePickerRangePositionContexthook:+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 theonClear,onSetToday,onAcceptandonCancelprops. You can use theusePickerActionsContextor theusePickerContexthooks 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 theisLandscapeprop. You can use theusePickerContexthook 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 theonChangeprop. You can use theusePickerActionsContextor theusePickerContexthooks 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 theisValidprop. You can use theuseIsValidValuehook 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
onOpenandonClosemethods have been replaced with a singlesetOpenmethod. 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];UseDateFieldComponentPropsimport { 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>;UseTimeFieldComponentPropsimport { 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>;UseDateTimeFieldComponentPropsimport { 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>;UseDateRangeFieldPropsimport { DateRangeManagerFieldInternalProps } from '@mui/x-date-pickers-pro/managers'; interface UseDateRangeFieldProps< TEnableAccessibleFieldDOMStructure extends boolean, > extends Omit< DateRangeManagerFieldInternalProps<TEnableAccessibleFieldDOMStructure>, 'unstableFieldRef' > {}UseMultiInputDateRangeFieldPropsimport { 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 {}UseMultiInputDateRangeFieldComponentPropsimport { 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;UseMultiInputTimeRangeFieldPropsimport { 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 {}UseMultiInputTimeRangeFieldComponentPropsimport { 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;UseMultiInputDateTimeRangeFieldPropsimport { 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 {}UseMultiInputDateTimeRangeFieldComponentPropsimport { 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';BaseSingleInputFieldPropsIf 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 {}
BaseMultiInputFieldPropsIf 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 {}
BasePickersTextFieldPropsIf 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> {}
ExportedUseClearableFieldPropsinterface ExportedUseClearableFieldProps { clearable?: boolean; onClear?: React.MouseEventHandler; }UseClearableFieldSlotsinterface UseClearableFieldSlots { clearIcon?: React.ElementType; clearButton?: React.ElementType; }UseClearableFieldSlotPropsimport { SlotComponentProps } from '@mui/utils/types'; 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>; }UseClearableFieldResponsetype 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 usefullTime12handfullTime24hinstead:<LocalizationProvider dateFormats={{ - fullTime: 'LT', + fullTime12h: 'hh:mm A', + fullTime24h: 'hh:mm', }} >keyboardDateTime- please usekeyboardDateTime12handkeyboardDateTime24hinstead:<LocalizationProvider dateFormats={{ - keyboardDateTime: 'DD.MM.YYYY | LT', + keyboardDateTime12h: 'DD.MM.YYYY | hh:mm A', + keyboardDateTime24h: 'DD.MM.YYYY | hh:mm', }} >