Migration from v8 to v9
This guide describes the changes needed to migrate the Date and Time Pickers from v8 to v9.
Introduction
This is a reference guide for upgrading @mui/x-date-pickers from v8 to v9.
Start using the new release
In package.json, change the version of the date pickers package to ^9.0.0.
-"@mui/x-date-pickers": "8.x.x",
+"@mui/x-date-pickers": "^9.0.0",
-"@mui/x-date-pickers-pro": "8.x.x",
+"@mui/x-date-pickers-pro": "^9.0.0",
Since v9 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 v8 to v9.
Run codemods
The preset-safe codemod will automatically adjust the bulk of your code to account for breaking changes in v9. You can run v9.0.0/pickers/preset-safe targeting only Date and Time Pickers or v9.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 v9.0.0/pickers/preset-safe <path>
# Target the other packages as well
npx @mui/x-codemod@latest v9.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 v9.0.0/pickers/preset-safe (or v9.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.
⚠️ Accessible DOM structure is now the default
The enableAccessibleFieldDOMStructure prop has been removed from all Picker and Field components.
The accessible DOM structure (section-based PickersTextField) introduced in v7 is now the only supported mode.
The legacy <input> based fallback is no longer available.
The preset-safe codemod will remove the prop from your code automatically—both as a direct prop and inside slotProps.field.
-<DatePicker enableAccessibleFieldDOMStructure label="Start date" />
+<DatePicker label="Start date" />
-<DatePicker enableAccessibleFieldDOMStructure={false} slots={{ textField: CustomTextField }} />
// CustomTextField must now be compatible with PickersTextField props
+<DatePicker slots={{ textField: CustomPickerTextField }} />
Slots breaking changes
⏩ Dialog slot
The dialog slot no longer receives the deprecated TransitionComponent, TransitionProps, and PaperProps props.
If you were passing a custom dialog slot, you need to update it to use slots and slotProps instead:
function CustomDialog({
- TransitionComponent,
- TransitionProps,
- PaperProps,
+ slots,
+ slotProps,
...props
}) {
// …your custom dialog implementation
}
<MobileDatePicker slots={{ dialog: CustomDialog }} />
Fields breaking changes
✅ Renamed fieldRef props
The unstableFieldRef, unstableStartFieldRef, and unstableEndFieldRef props have been renamed to fieldRef, startFieldRef, and endFieldRef respectively.
For Picker components, fieldRef should now be passed through the slotProps.field.fieldRef prop.
// Before
<DateField unstableFieldRef={fieldRef} />
<DatePicker slotProps={{ field: { unstableFieldRef: fieldRef } }} />
// After
<DateField fieldRef={fieldRef} />
<DatePicker slotProps={{ field: { fieldRef: fieldRef } }} />
const CustomField = (props: MultiInputDateRangeFieldProps<true>) => (
<MultiInputDateRangeField
{...props}
startFieldRef={startFieldRef}
endFieldRef={endFieldRef}
/>
);
<DateRangePicker slots={{ field: CustomField }} />;
New clearValue() method on FieldRef
The FieldRef object now includes a clearValue() method to programmatically clear the field's value.
const fieldRef = React.useRef<FieldRef<PickerValue>>(null);
// ...
<DateField fieldRef={fieldRef} />;
// ...
fieldRef.current?.clearValue();
⚠️ textField slot type change
The textField slot prop on Picker and Field components now only accepts PickersTextFieldProps.
It no longer accepts TextFieldProps from @mui/material.
Components breaking changes
⚠️ Day slot
The PickerDay2 and DateRangePickerDay2 components have been renamed to PickerDay and DateRangePickerDay respectively, replacing the old components.
They are now the default components for the day slot, so you no longer need to pass them to slots.
The PickerDay and DateRangePickerDay components now use display: flex.
⚠️ Component structure change
The PickerDay and DateRangePickerDay components have been simplified and now use a single ButtonBase element.
Previously, they used multiple nested elements to render the selection and preview highlights.
These highlights are now rendered using ::before and ::after pseudo-elements on the root element.
This change might affect your custom styles if you were targeting the nested elements.
For example, in DateRangePickerDay, the day class has been removed as there is no longer a separate element for the day content.
⚠️ DateRangePickerDay selection behavior
The isDaySelected condition in DateRangePickerDay has been updated to also include individually selected days, not just days within a valid range.
Previously, a day was only considered "selected" (receiving the .Mui-selected class) if it was part of a fully defined and valid range.
Now, if a DateRangePicker has only one date selected (for example [Jan 1st, null]), that date will now visually appear as selected with the primary color circle, even if the range is not yet complete.
This makes the behavior more consistent with the single date picker (PickerDay).
This change might affect your custom CSS if you were targeting the .Mui-selected state of DateRangePickerDay and expected it to only be present for complete ranges.
⚠️ disableMargin prop removal
The disableMargin prop has been removed from PickerDay and DateRangePickerDay components.
In v8, DateRangePickerDay internally hardcoded disableMargin={true} on the PickersDay component.
In v9, by default, both components will now have horizontal margins.
If you want to remove the margins, you can use the --PickerDay-horizontalMargin CSS variable:
<DatePicker
slotProps={{
day: { sx: { '--PickerDay-horizontalMargin': 0 } },
}}
/>
✅ Renamed PickersDay
The PickersDay component has been renamed to PickerDay to be consistent with the other components.
The theme component name has also been updated from MuiPickersDay to MuiPickerDay.
All associated types and classes have been renamed as well (for example, PickersDayProps to PickerDayProps, pickersDayClasses to pickerDayClasses).
// Before
import { PickersDay, pickersDayClasses } from '@mui/x-date-pickers/PickersDay';
const theme = createTheme({
components: {
MuiPickersDay: {
styleOverrides: {
root: { color: 'red' },
},
},
},
});
// After
import { PickerDay, pickerDayClasses } from '@mui/x-date-pickers/PickerDay';
const theme = createTheme({
components: {
MuiPickerDay: {
styleOverrides: {
root: { color: 'red' },
},
},
},
});
✅ DateRangePickerDay classes
The DateRangePickerDay classes have been updated to be more consistent with the other components and to better describe their purpose.
Several keys have been removed from the DateRangePickerDayClasses interface.
day,notSelectedDate, anddayOutsideRangeIntervalhave been removed.rangeIntervalDayHighlight,rangeIntervalDayHighlightStart, andrangeIntervalDayHighlightEndhave been removed. You can now useselectionStartandselectionEndinstead.rangeIntervalDayPreview,rangeIntervalDayPreviewStart, andrangeIntervalDayPreviewEndhave been removed. You can now usepreviewStartandpreviewEndinstead.dayInsideRangeIntervalhas been removed. You can now useinsideSelectioninstead.rangeIntervalPreviewhas been removed. You can now useinsidePreviewinginstead.outsideCurrentMonthhas been renamed todayOutsideMonth.hiddenDayFillerandhiddenDaySpacingFillerhave been renamed tofillerCell.firstVisibleCellandlastVisibleCellare now utility classes available on bothPickerDayandDateRangePickerDayroot elements.
If you have custom styleOverrides for these classes, you need to update them to use the new class names.
// Before
const theme = createTheme({
components: {
MuiDateRangePickerDay: {
styleOverrides: {
rangeIntervalDayHighlight: { backgroundColor: 'red' },
dayInsideRangeInterval: { color: 'blue' },
},
},
},
});
// After
const theme = createTheme({
components: {
MuiDateRangePickerDay: {
styleOverrides: {
selectionStart: { backgroundColor: 'red' },
selectionEnd: { backgroundColor: 'red' },
insideSelection: { color: 'blue' },
},
},
},
});
✅ PickerDay classes
Several keys have been removed from the PickerDayClasses interface:
dayWithMarginanddayWithoutMarginhave been removed.hiddenDayFillerandhiddenDaySpacingFillerhave been renamed tofillerCell.outsideCurrentMonthhas been renamed todayOutsideMonth.
⏩ data-testid changes
The data-testid attributes on several components have been updated, which may break your unit or integration tests if you are querying for these specific IDs.
- In
DateRangePickerDay, thedata-testid="DateRangeHighlight"attribute that was previously on a nested<span>has been moved to the root element.- When a day is highlighted, its
data-testidwill beDateRangeHighlightinstead ofDateRangePickerDay. - Tests querying for a nested button inside
DateRangeHighlightwill break asDateRangePickerDayis now a single element.
- When a day is highlighted, its
- The
DateRangePreviewtest ID has been removed entirely. PickerDay(formerlyPickersDay) now respects a customdata-testidprop if provided, falling back to its default value"day".
✅ Drop deprecated PickersTextField props
The legacy InputProps, inputProps, InputLabelProps and FormHelperTextProps props have been removed from PickersTextField and from every Picker / Field component.
They were the last remnants of the old Material UI TextField API.
The replacement is the new slotProps shape, which mirrors the Material UI v9 TextField API:
| Removed prop | New location |
|---|---|
InputProps |
slotProps.input |
inputProps |
slotProps.htmlInput |
InputLabelProps |
slotProps.inputLabel |
FormHelperTextProps |
slotProps.formHelperText |
On PickersTextField the new keys live directly under slotProps:
<PickersTextField
- InputProps={{ startAdornment: <CakeIcon /> }}
- inputProps={{ 'data-testid': 'input' }}
+ slotProps={{
+ input: { startAdornment: <CakeIcon /> },
+ htmlInput: { 'data-testid': 'input' },
+ }}
/>
On Picker and Field components they are nested inside slotProps.textField.slotProps:
<DateField
- InputProps={{ name: 'birthday' }}
- inputProps={{ 'data-testid': 'input' }}
+ slotProps={{
+ textField: {
+ slotProps: {
+ input: { name: 'birthday' },
+ htmlInput: { 'data-testid': 'input' },
+ },
+ },
+ }}
/>
<DatePicker
- slotProps={{ textField: { InputProps: { name: 'date' } } }}
+ slotProps={{ textField: { slotProps: { input: { name: 'date' } } } }}
/>
The preset-safe codemod (or the standalone migrate-text-field-props codemod) performs this rewrite automatically:
npx @mui/x-codemod@next v9.0.0/pickers/migrate-text-field-props <path>
⏩ LocalizationProvider breaking changes
⏩ utils field removed from the adapter context value
The deprecated utils field has been removed from the PickersAdapterContextValue interface (the value exposed by the internal pickers adapter context).
Use the adapter field instead — it holds the exact same reference.
The recommended way to access the adapter remains the usePickerAdapter hook.
import { usePickerAdapter } from '@mui/x-date-pickers/hooks';
const adapter = usePickerAdapter();
-// Previously, you could also read `utils` from the internal context value.
⏩ MuiPickersAdapterContext export removed
The deprecated MuiPickersAdapterContext named export has been removed from @mui/x-date-pickers and @mui/x-date-pickers-pro.
Use the usePickerAdapter hook to access the adapter instead of reading the context directly.
-import { MuiPickersAdapterContext } from '@mui/x-date-pickers/LocalizationProvider';
-import * as React from 'react';
-
-const adapter = React.useContext(MuiPickersAdapterContext)?.adapter;
+import { usePickerAdapter } from '@mui/x-date-pickers/hooks';
+
+const adapter = usePickerAdapter();
⏩ Removed types
⏩ UseDateManagerParameters and UseDateTimeManagerParameters
The UseDateManagerParameters and UseDateTimeManagerParameters interfaces have been removed.
They only contained the enableAccessibleFieldDOMStructure prop, which has been removed in v9.
The useDateManager and useDateTimeManager hooks no longer accept any parameters.
-import { UseDateManagerParameters } from '@mui/x-date-pickers/managers';
-import { UseDateTimeManagerParameters } from '@mui/x-date-pickers/managers';
⏩ PickerManager generic change
The PickerManager interface now has 4 type parameters instead of 5.
The TEnableAccessibleFieldDOMStructure type parameter has been removed.
-PickerManager<TValue, TError, TValidationProps, TEnableAccessibleFieldDOMStructure, TFieldInternalProps>
+PickerManager<TValue, TError, TValidationProps, TFieldInternalProps>
⏩ Picker and Field component type parameters
All Picker and Field component prop types no longer have the TEnableAccessibleFieldDOMStructure generic parameter.
If you were passing this type parameter explicitly, remove it:
-type MyPickerProps = DatePickerProps<true>;
+type MyPickerProps = DatePickerProps;
-type MyFieldProps = DateFieldProps<true>;
+type MyFieldProps = DateFieldProps;
This applies to all Picker component prop types (DatePickerProps, DateTimePickerProps, TimePickerProps, DateRangePickerProps, etc.), all Field component prop types (DateFieldProps, TimeFieldProps, etc.), and their Desktop/Mobile/Static variants.
The field hooks also no longer accept this type parameter:
-const response = useDateField<true, typeof props>(props);
+const response = useDateField<typeof props>(props);