diff --git a/.circleci/config.yml b/.circleci/config.yml
index 72bff75bfe51..5ef43ce3e635 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -36,7 +36,7 @@ default-job: &default-job
REACT_VERSION: << parameters.react-version >>
working_directory: /tmp/mui
docker:
- - image: cimg/node:18.20
+ - image: cimg/node:20.17
# CircleCI has disabled the cache across forks for security reasons.
# Following their official statement, it was a quick solution, they
# are working on providing this feature back with appropriate security measures.
diff --git a/.codesandbox/ci.json b/.codesandbox/ci.json
index f46a89cf5698..91008eca7dc2 100644
--- a/.codesandbox/ci.json
+++ b/.codesandbox/ci.json
@@ -1,7 +1,7 @@
{
"buildCommand": "build:codesandbox",
"installCommand": "install:codesandbox",
- "node": "18",
+ "node": "20",
"packages": [
"packages/x-license",
"packages/x-data-grid",
diff --git a/babel.config.js b/babel.config.js
index 6d812eba0163..40d90dfbaae1 100644
--- a/babel.config.js
+++ b/babel.config.js
@@ -89,8 +89,8 @@ module.exports = function getBabelConfig(api) {
'@babel/plugin-transform-runtime',
{
useESModules,
- // any package needs to declare 7.4.4 as a runtime dependency. default is ^7.0.0
- version: '^7.4.4',
+ // any package needs to declare 7.25.0 as a runtime dependency. default is ^7.0.0
+ version: process.env.MUI_BABEL_RUNTIME_VERSION || '^7.25.0',
},
],
[
diff --git a/docs/data/common-concepts/custom-components/CustomSlot.js b/docs/data/common-concepts/custom-components/CustomSlot.js
new file mode 100644
index 000000000000..9740551294d5
--- /dev/null
+++ b/docs/data/common-concepts/custom-components/CustomSlot.js
@@ -0,0 +1,13 @@
+import * as React from 'react';
+import FlightTakeoffIcon from '@mui/icons-material/FlightTakeoff';
+import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
+import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
+import { DatePicker } from '@mui/x-date-pickers/DatePicker';
+
+export default function CustomSlot() {
+ return (
+
+
+
+ );
+}
diff --git a/docs/data/common-concepts/custom-components/CustomSlot.tsx b/docs/data/common-concepts/custom-components/CustomSlot.tsx
new file mode 100644
index 000000000000..9740551294d5
--- /dev/null
+++ b/docs/data/common-concepts/custom-components/CustomSlot.tsx
@@ -0,0 +1,13 @@
+import * as React from 'react';
+import FlightTakeoffIcon from '@mui/icons-material/FlightTakeoff';
+import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
+import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
+import { DatePicker } from '@mui/x-date-pickers/DatePicker';
+
+export default function CustomSlot() {
+ return (
+
+
+
+ );
+}
diff --git a/docs/data/common-concepts/custom-components/CustomSlot.tsx.preview b/docs/data/common-concepts/custom-components/CustomSlot.tsx.preview
new file mode 100644
index 000000000000..d5fe738985f4
--- /dev/null
+++ b/docs/data/common-concepts/custom-components/CustomSlot.tsx.preview
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/docs/data/common-concepts/custom-components/CustomSlotAndSlotProps.js b/docs/data/common-concepts/custom-components/CustomSlotAndSlotProps.js
new file mode 100644
index 000000000000..a6c3a5e036b7
--- /dev/null
+++ b/docs/data/common-concepts/custom-components/CustomSlotAndSlotProps.js
@@ -0,0 +1,20 @@
+import * as React from 'react';
+import FlightTakeoffIcon from '@mui/icons-material/FlightTakeoff';
+import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
+import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
+import { DatePicker } from '@mui/x-date-pickers/DatePicker';
+
+export default function CustomSlotAndSlotProps() {
+ return (
+
+
+
+ );
+}
diff --git a/docs/data/common-concepts/custom-components/CustomSlotAndSlotProps.tsx b/docs/data/common-concepts/custom-components/CustomSlotAndSlotProps.tsx
new file mode 100644
index 000000000000..a6c3a5e036b7
--- /dev/null
+++ b/docs/data/common-concepts/custom-components/CustomSlotAndSlotProps.tsx
@@ -0,0 +1,20 @@
+import * as React from 'react';
+import FlightTakeoffIcon from '@mui/icons-material/FlightTakeoff';
+import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
+import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
+import { DatePicker } from '@mui/x-date-pickers/DatePicker';
+
+export default function CustomSlotAndSlotProps() {
+ return (
+
+
+
+ );
+}
diff --git a/docs/data/common-concepts/custom-components/CustomSlotAndSlotProps.tsx.preview b/docs/data/common-concepts/custom-components/CustomSlotAndSlotProps.tsx.preview
new file mode 100644
index 000000000000..663cf8c57329
--- /dev/null
+++ b/docs/data/common-concepts/custom-components/CustomSlotAndSlotProps.tsx.preview
@@ -0,0 +1,8 @@
+
\ No newline at end of file
diff --git a/docs/data/common-concepts/custom-components/CustomSlotProps.js b/docs/data/common-concepts/custom-components/CustomSlotProps.js
new file mode 100644
index 000000000000..686f4e6898f8
--- /dev/null
+++ b/docs/data/common-concepts/custom-components/CustomSlotProps.js
@@ -0,0 +1,18 @@
+import * as React from 'react';
+import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
+import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
+import { DatePicker } from '@mui/x-date-pickers/DatePicker';
+
+export default function CustomSlotProps() {
+ return (
+
+
+
+ );
+}
diff --git a/docs/data/common-concepts/custom-components/CustomSlotProps.tsx b/docs/data/common-concepts/custom-components/CustomSlotProps.tsx
new file mode 100644
index 000000000000..686f4e6898f8
--- /dev/null
+++ b/docs/data/common-concepts/custom-components/CustomSlotProps.tsx
@@ -0,0 +1,18 @@
+import * as React from 'react';
+import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
+import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
+import { DatePicker } from '@mui/x-date-pickers/DatePicker';
+
+export default function CustomSlotProps() {
+ return (
+
+
+
+ );
+}
diff --git a/docs/data/common-concepts/custom-components/CustomSlotProps.tsx.preview b/docs/data/common-concepts/custom-components/CustomSlotProps.tsx.preview
new file mode 100644
index 000000000000..023ce6ddb493
--- /dev/null
+++ b/docs/data/common-concepts/custom-components/CustomSlotProps.tsx.preview
@@ -0,0 +1,7 @@
+
\ No newline at end of file
diff --git a/docs/data/common-concepts/custom-components/CustomSlotPropsCallback.js b/docs/data/common-concepts/custom-components/CustomSlotPropsCallback.js
new file mode 100644
index 000000000000..e1272f2776ba
--- /dev/null
+++ b/docs/data/common-concepts/custom-components/CustomSlotPropsCallback.js
@@ -0,0 +1,18 @@
+import * as React from 'react';
+import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
+import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
+import { DatePicker } from '@mui/x-date-pickers/DatePicker';
+
+export default function CustomSlotPropsCallback() {
+ return (
+
+ ({
+ color: ownerState.open ? 'secondary' : 'primary',
+ }),
+ }}
+ />
+
+ );
+}
diff --git a/docs/data/common-concepts/custom-components/CustomSlotPropsCallback.tsx b/docs/data/common-concepts/custom-components/CustomSlotPropsCallback.tsx
new file mode 100644
index 000000000000..e1272f2776ba
--- /dev/null
+++ b/docs/data/common-concepts/custom-components/CustomSlotPropsCallback.tsx
@@ -0,0 +1,18 @@
+import * as React from 'react';
+import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
+import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
+import { DatePicker } from '@mui/x-date-pickers/DatePicker';
+
+export default function CustomSlotPropsCallback() {
+ return (
+
+ ({
+ color: ownerState.open ? 'secondary' : 'primary',
+ }),
+ }}
+ />
+
+ );
+}
diff --git a/docs/data/common-concepts/custom-components/CustomSlotPropsCallback.tsx.preview b/docs/data/common-concepts/custom-components/CustomSlotPropsCallback.tsx.preview
new file mode 100644
index 000000000000..100188718fae
--- /dev/null
+++ b/docs/data/common-concepts/custom-components/CustomSlotPropsCallback.tsx.preview
@@ -0,0 +1,7 @@
+ ({
+ color: ownerState.open ? 'secondary' : 'primary',
+ }),
+ }}
+/>
\ No newline at end of file
diff --git a/docs/data/common-concepts/custom-components/TypescriptCasting.js b/docs/data/common-concepts/custom-components/TypescriptCasting.js
new file mode 100644
index 000000000000..4d0346ef92f1
--- /dev/null
+++ b/docs/data/common-concepts/custom-components/TypescriptCasting.js
@@ -0,0 +1,63 @@
+import * as React from 'react';
+
+import Stack from '@mui/material/Stack';
+import FormControlLabel from '@mui/material/FormControlLabel';
+import Switch from '@mui/material/Switch';
+import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
+import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
+import { DateCalendar } from '@mui/x-date-pickers/DateCalendar';
+
+import { PickersCalendarHeader } from '@mui/x-date-pickers/PickersCalendarHeader';
+
+function DisplayWeekNumberToggle({ value, onChange }) {
+ return (
+ onChange(event.target.checked)}
+ />
+ }
+ label="Display week number"
+ />
+ );
+}
+
+function CustomCalendarHeader({
+ displayWeekNumber,
+ setDisplayWeekNumber,
+ ...other
+}) {
+ return (
+
+
+
+
+ );
+}
+
+export default function TypescriptCasting() {
+ const [displayWeekNumber, setDisplayWeekNumber] = React.useState(false);
+
+ return (
+
+
+
+ );
+}
diff --git a/docs/data/common-concepts/custom-components/TypescriptCasting.tsx b/docs/data/common-concepts/custom-components/TypescriptCasting.tsx
new file mode 100644
index 000000000000..2d68d2c1e6be
--- /dev/null
+++ b/docs/data/common-concepts/custom-components/TypescriptCasting.tsx
@@ -0,0 +1,80 @@
+import * as React from 'react';
+import { Dayjs } from 'dayjs';
+import Stack from '@mui/material/Stack';
+import FormControlLabel from '@mui/material/FormControlLabel';
+import Switch from '@mui/material/Switch';
+import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
+import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
+import {
+ DateCalendar,
+ DateCalendarSlots,
+ DateCalendarSlotProps,
+} from '@mui/x-date-pickers/DateCalendar';
+import { PropsFromSlot } from '@mui/x-date-pickers/models';
+import { PickersCalendarHeader } from '@mui/x-date-pickers/PickersCalendarHeader';
+
+function DisplayWeekNumberToggle({
+ value,
+ onChange,
+}: {
+ value: boolean;
+ onChange: (value: boolean) => void;
+}) {
+ return (
+ onChange(event.target.checked)}
+ />
+ }
+ label="Display week number"
+ />
+ );
+}
+
+interface CustomCalendarHeaderProps
+ extends PropsFromSlot['calendarHeader']> {
+ displayWeekNumber: boolean;
+ setDisplayWeekNumber: (displayWeekNumber: boolean) => void;
+}
+
+function CustomCalendarHeader({
+ displayWeekNumber,
+ setDisplayWeekNumber,
+ ...other
+}: CustomCalendarHeaderProps) {
+ return (
+
+
+
+
+ );
+}
+
+export default function TypescriptCasting() {
+ const [displayWeekNumber, setDisplayWeekNumber] = React.useState(false);
+
+ return (
+
+ ['calendarHeader'],
+ }}
+ slotProps={{
+ calendarHeader: {
+ displayWeekNumber,
+ setDisplayWeekNumber,
+ } as DateCalendarSlotProps['calendarHeader'],
+ }}
+ />
+
+ );
+}
diff --git a/docs/data/common-concepts/custom-components/TypescriptCasting.tsx.preview b/docs/data/common-concepts/custom-components/TypescriptCasting.tsx.preview
new file mode 100644
index 000000000000..461108b0d9c5
--- /dev/null
+++ b/docs/data/common-concepts/custom-components/TypescriptCasting.tsx.preview
@@ -0,0 +1,14 @@
+['calendarHeader'],
+ }}
+ slotProps={{
+ calendarHeader: {
+ displayWeekNumber,
+ setDisplayWeekNumber,
+ } as DateCalendarSlotProps['calendarHeader'],
+ }}
+/>
\ No newline at end of file
diff --git a/docs/data/common-concepts/custom-components/custom-components.md b/docs/data/common-concepts/custom-components/custom-components.md
new file mode 100644
index 000000000000..28e37c605637
--- /dev/null
+++ b/docs/data/common-concepts/custom-components/custom-components.md
@@ -0,0 +1,252 @@
+# Custom slots and subcomponents
+
+
Learn how to override parts of the MUI X components.
+
+## What is a slot?
+
+A slot is a part of a component that can be [overridden](/x/common-concepts/custom-components/#how-to-override-a-slot) and/or [customized](/x/common-concepts/custom-components/#how-to-customize-a-slot).
+
+Some of those slots allow you to provide your own UI primitives to the MUI X components.
+This is the role of all the `baseXXX` component on the `DataGrid` component (`baseButton`, `baseSelect`, ...).
+These slots receive props that should be as generic as possible so that it is easy to interface any other design system.
+
+Other slots allow you to override parts of the MUI X UI components with a custom UI built specifically for this component.
+This is the role of slots like `calendarHeader` on the `DateCalendar` component or `item` on the `RichTreeView` component.
+These slots receive props specific to this part of the UI and will most likely not be re-use throughout your application.
+
+## Basic usage
+
+### How to override a slot?
+
+You can override a slot by providing a custom component to the `slots` prop:
+
+{{"demo": "CustomSlot.js"}}
+
+### How to customize a slot?
+
+You can pass props to any slot using the `slotProps` prop:
+
+{{"demo": "CustomSlotProps.js"}}
+
+You can also use both `slots` and `slotProps` on the same component:
+
+{{"demo": "CustomSlotAndSlotProps.js"}}
+
+Most slots also support a callback version of `slotProps`.
+This callback receives an object that contains information about the current state of the component,
+that information can vary depending on the slot being used:
+
+{{"demo": "CustomSlotPropsCallback.js"}}
+
+## Correct usage
+
+A slot is a React component; therefore, it should keep the same JavaScript reference between two renders.
+If the JavaScript reference of component changes between two renders, React will remount it.
+You can avoid it by not inlining the component definition in the `slots` prop.
+
+The first two examples below are buggy because the calendar header will remount after each keystroke, leading to a loss of focus.
+
+```jsx
+// ❌ The `calendarHeader` slot is re-defined each time the parent component renders,
+// causing the component to remount.
+function MyApp() {
+ const [name, setName] = React.useState('');
+ return (
+ (
+ setName(event.target.value)} />
+ ),
+ }}
+ />
+ );
+}
+```
+
+```jsx
+// ❌ The `calendarHeader` slot is re-defined each time `name` is updated,
+// causing the component to remount.
+function MyApp() {
+ const [name, setName] = React.useState('');
+
+ const CustomCalendarHeader = React.useCallback(
+ () => setName(event.target.value)} />,
+ [name],
+ );
+
+ return ;
+}
+```
+
+```jsx
+// ✅ The `calendarHeader` slot is defined only once, it will never remount.
+const CustomCalendarHeader = ({ name, setName }) => (
+ setName(event.target.value)} />
+);
+
+function MyApp() {
+ const [name, setName] = React.useState('');
+ return (
+
+ );
+}
+```
+
+## Usage with TypeScript
+
+### Type custom slots
+
+If you want to ensure type safety on your custom slot component,
+you can declare your component using the `PropsFromSlot` interface:
+
+```tsx
+function CustomCalendarHeader({
+ currentMonth,
+}: PropsFromSlot['calendarHeader']>) {
+ return
{currentMonth?.format('MM-DD-YYYY')}
;
+}
+```
+
+:::success
+The `PropsFromSlot` is exported from every package that supports slots:
+
+```ts
+import { PropsFromSlot } from '@mui/x-data-grid/models';
+import { PropsFromSlot } from '@mui/x-date-pickers/models';
+// ...
+```
+
+It takes the slot type (as defined in the `slots` prop of your component) and returns the props that the slot receives.
+
+```ts
+import { Dayjs } from 'dayjs';
+import { PropsFromSlot, GridSlots } from '@mui/x-data-grid';
+import { DateCalendarSlots } from '@mui/x-date-pickers';
+
+type ToolbarProps = PropsFromSlot;
+
+// Most of the picker slots interfaces need to receive the date type as a generic.
+type CalendarHeaderProps = PropsFromSlot['calendarHeader']>;
+```
+
+:::
+
+### Using additional props
+
+If you are passing additional props to your slot, you can add them to the props your custom component receives:
+
+```ts
+interface CustomCalendarHeaderProps
+ extends PropsFromSlot['calendarHeader']> {
+ displayWeekNumber: boolean;
+ setDisplayWeekNumber: (displayWeekNumber: boolean) => void;
+}
+```
+
+You can then use these props in your custom component and access both the props provided by the host component
+and the props you added:
+
+```tsx
+function CustomCalendarHeader({
+ displayWeekNumber,
+ setDisplayWeekNumber,
+ ...other
+}: CustomCalendarHeaderProps) {
+ return (
+
+
+
+
+ );
+}
+```
+
+If your custom component has a different type than the default one, you will need to cast it to the correct type.
+This can happen if you pass additional props to your custom component using `slotProps`.
+If we take the example of the `calendarHeader` slot, you can cast your custom component as below:
+
+```tsx
+function MyApp() {
+ const [displayWeekNumber, setDisplayWeekNumber] = React.useState(false);
+ return (
+ ['calendarHeader'],
+ }}
+ slotProps={{
+ calendarHeader: {
+ displayWeekNumber,
+ setDisplayWeekNumber,
+ } as DateCalendarSlotProps['calendarHeader'],
+ }}
+ />
+ );
+}
+```
+
+{{"demo": "TypescriptCasting.js", "defaultCodeOpen": false}}
+
+### Using module augmentation
+
+If you are using one of the data grid packages,
+you can also use [module augmentation](/x/react-data-grid/components/#custom-slot-props-with-typescript) to let TypeScript know about your custom props:
+
+```ts
+declare module '@mui/x-data-grid' {
+ interface ToolbarPropsOverrides {
+ name: string;
+ setName: (name: string) => void;
+ }
+}
+```
+
+You can then use your custom slot without any type casting:
+
+```tsx
+function CustomToolbar({ name, setName }: PropsFromSlot) {
+ return setName(event.target.value)} />;
+}
+
+function MyApp() {
+ const [name, setName] = React.useState('');
+ return (
+
+ );
+}
+```
+
+See [Data Grid - Custom slots and subcomponents—Custom slot props with TypeScript](/x/react-data-grid/components/#custom-slot-props-with-typescript) for more details.
+
+:::warning
+The module augmentation feature isn't implemented yet for the other sets of components. It's coming.
+
+- 👍 Upvote [issue 9775](https://github.com/mui/mui-x/issues/9775) if you want to see it land faster on the Date and Time Pickers.
+- 👍 Upvote [issue 14063](https://github.com/mui/mui-x/issues/14063) if you want to see it land faster on the Charts.
+- 👍 Upvote [issue 14062](https://github.com/mui/mui-x/issues/14062) if you want to see it land faster on the Tree View.
+
+ :::
+
+## Slots of the X components
+
+You can find the list of slots in the API documentation of each component (e.g. [DataGrid](/x/api/data-grid/data-grid/#slots), [DatePicker](/x/api/date-pickers/date-picker/#slots), [BarChart](/x/api/charts/bar-chart/#slots) or [RichTreeView](/x/api/tree-view/rich-tree-view/#slots)).
+
+Most of the slots have a standalone doc example to show how to use them:
+
+- [Data Grid—Custom slots and subcomponents](/x/react-data-grid/components/)
+- [Date Picker—Custom slots and subcomponents](/x/react-date-pickers/custom-components/)
+- [RichTreeView—Customization](/x/react-tree-view/rich-tree-view/customization/) / [SimpleTreeView—Customization](/x/react-tree-view/simple-tree-view/customization/)
diff --git a/docs/data/data-grid/column-menu/column-menu.md b/docs/data/data-grid/column-menu/column-menu.md
index fcbe4a8b40dd..cb20213f0d60 100644
--- a/docs/data/data-grid/column-menu/column-menu.md
+++ b/docs/data/data-grid/column-menu/column-menu.md
@@ -126,7 +126,7 @@ As a reference, here are the column menu `slots` along with the default item com
## Custom menu component
-You can also customize and replace the column menu by [passing a fully custom component](/x/react-data-grid/components/#overriding-components) to the `columnMenu` slot of the Data Grid. If you want to add some of the default menu items to your custom component, you can import and re-use them.
+You can also customize and replace the column menu by [passing a fully custom component](/x/react-data-grid/components/#component-slots) to the `columnMenu` slot of the Data Grid. If you want to add some of the default menu items to your custom component, you can import and re-use them.
{{"demo": "CustomColumnMenuGrid.js", "bg": "inline"}}
diff --git a/docs/data/data-grid/components/components.md b/docs/data/data-grid/components/components.md
index 6d78d7487beb..af1eb59c460f 100644
--- a/docs/data/data-grid/components/components.md
+++ b/docs/data/data-grid/components/components.md
@@ -1,43 +1,8 @@
-# Data Grid - Custom subcomponents
+# Data Grid - Custom slots and subcomponents
-
The grid is highly customizable. Override components using the slots prop.
+
Learn how to override parts of the grid.
-## Overriding components
-
-As part of the customization API, the Data Grid allows you to override internal components with the `slots` prop.
-The prop accepts an object of type [`GridSlotsComponent`](/x/api/data-grid/data-grid/#slots).
-
-If you wish to pass additional props in a component slot, you can do it using the `slotProps` prop.
-This prop is of type `GridSlotsComponentsProps`. Note that if you do and you use TypeScript, you'll need to cast your custom component so it can fit in the slot type.
-
-As an example, you could override the column menu and pass additional props as below.
-
-```tsx
-
-```
-
-If you want to ensure type safety, you can declare your component using the slot props typings:
-
-```tsx
-import { GridSlotProps } from '@mui/x-data-grid';
-
-function MyCustomColumnMenu(
- props: GridSlotProps['columnMenu'] & { background: string; counter: number },
-) {
- // ...
-}
-```
-
-### Interacting with the data grid
+## Interacting with the data grid
The grid exposes two hooks to help you access the data grid data while overriding component slots.
@@ -64,7 +29,12 @@ function CustomPagination() {
## Component slots
-The full list of overridable component slots can be found on the [`GridSlotsComponent`](/x/api/data-grid/data-grid/#slots) API page.
+:::success
+
+- See [Common concepts—Custom slots and subcomponents](/x/common-concepts/custom-components/) to learn how to use slots.
+- See [`GridSlotsComponent`](/x/api/data-grid/data-grid/#slots) to learn about the available slots.
+
+ :::
### Column menu
@@ -153,22 +123,13 @@ As any component slot, every icon can be customized. However, it is not yet poss
See the [Overlays](/x/react-data-grid/overlays/) documentation on how to customize the `loadingOverlay`, `noRowsOverlay`, and `noResultsOverlay`.
-## Slot props
-
-To override default props or pass custom props to slot components, use the `slotProps` prop.
+## Custom slot props with TypeScript
-```tsx
-
-```
+:::success
+This section focuses on module augmentation.
-### Custom slot props with TypeScript
+See [Custom slots and subcomponents—Usage with TypeScript](/x/common-concepts/custom-components/#usage-with-typescript) if you don't want to use this approach.
+:::
If the custom component requires additional props to work properly, TypeScript may throw type errors.
To solve these type errors, use [module augmentation](https://www.typescriptlang.org/docs/handbook/declaration-merging.html#module-augmentation) to enhance the props interface.
@@ -201,7 +162,7 @@ declare module '@mui/x-data-grid' {
}}
slotProps={{
toolbar: {
- // props required by CustomGridToolbar
+ // props used by CustomGridToolbar
someCustomString: 'Hello',
someCustomNumber: 42,
},
@@ -225,7 +186,7 @@ declare module '@mui/x-data-grid-pro' {
}}
slotProps={{
toolbar: {
- // props required by CustomGridToolbar
+ // props used by CustomGridToolbar
someCustomString: 'Hello',
someCustomNumber: 42,
},
@@ -249,7 +210,7 @@ declare module '@mui/x-data-grid-premium' {
}}
slotProps={{
toolbar: {
- // props required by CustomGridToolbar
+ // props used by CustomGridToolbar
someCustomString: 'Hello',
someCustomNumber: 42,
},
diff --git a/docs/data/data-grid/filtering/customization.md b/docs/data/data-grid/filtering/customization.md
index 83566d25d21e..5d55919b988e 100644
--- a/docs/data/data-grid/filtering/customization.md
+++ b/docs/data/data-grid/filtering/customization.md
@@ -147,7 +147,7 @@ const ratingColumnType: GridColTypeDef = {
## Custom filter panel
-You can customize the rendering of the filter panel as shown in [the component section](/x/react-data-grid/components/#overriding-components) of the documentation.
+You can customize the rendering of the filter panel as shown in [the component section](/x/react-data-grid/components/#component-slots) of the documentation.
### Customize the filter panel content
diff --git a/docs/data/date-pickers/custom-components/custom-components.md b/docs/data/date-pickers/custom-components/custom-components.md
index 65034ecb8882..023e89cb0a05 100644
--- a/docs/data/date-pickers/custom-components/custom-components.md
+++ b/docs/data/date-pickers/custom-components/custom-components.md
@@ -6,94 +6,17 @@ components: DateTimePickerTabs, PickersActionBar, DatePickerToolbar, TimePickerT
# Custom slots and subcomponents
-
Learn how to override the default DOM structure of the Date and Time Pickers.
+
Learn how to override parts of the Date and Time Pickers.
:::info
The components that can be customized are listed under `slots` section in Date and Time Pickers [API Reference](/x/api/date-pickers/).
For example, available Date Picker slots can be found [here](/x/api/date-pickers/date-picker/#slots).
:::
-## Overriding slot components
-
-You can override the internal elements of the component (known as "slots") using the `slots` prop.
-
-Use the `slotProps` prop if you need to pass additional props to a component slot.
-
-As an example, you could override the `ActionBar` and pass additional props to the custom component as shown below:
-
-```jsx
- with a custom one
- actionBar: CustomActionBar,
- }}
- slotProps={{
- // pass props `actions={['clear']}` to the actionBar slot
- actionBar: { actions: ['clear'] },
- }}
-/>
-```
-
-To modify components position, have a look at the [custom layout](/x/react-date-pickers/custom-layout/) docs page.
-
-### Recommended usage
-
:::success
-Remember to pass a reference to the component instead of an inline render function and define it outside the main component.
-This ensures that the component is not remounted on every update.
+See [Common concepts—Custom slots and subcomponents](/x/common-concepts/custom-components/) to learn how to use slots.
:::
-The first two examples below are buggy because the toolbar will remount after each keystroke, leading to a loss of focus.
-
-```jsx
-// ❌ The `toolbar` slot is re-defined each time the parent component renders,
-// causing the component to remount.
-function MyApp() {
- return (
- (
- setName(event.target.value)} />
- ),
- }}
- />
- );
-}
-```
-
-```jsx
-// ❌ The `toolbar` slot is re-defined each time `name` is updated,
-// causing the component to remount.
-function MyApp() {
- const [name, setName] = React.useState('');
-
- const CustomToolbar = React.useCallback(
- () => setName(event.target.value)} />,
- [name],
- );
-
- return ;
-}
-```
-
-```jsx
-// ✅ The `toolbar` slot is defined only once, it will never remount.
-const CustomToolbar = ({ name, setName }) => (
- setName(event.target.value)} />
-);
-
-function MyApp() {
- const [name, setName] = React.useState('');
- return (
-
- );
-}
-```
-
## Action bar
### Component props
diff --git a/docs/data/date-pickers/custom-field/custom-field.md b/docs/data/date-pickers/custom-field/custom-field.md
index bb3301d7bf66..b58ea51d833f 100644
--- a/docs/data/date-pickers/custom-field/custom-field.md
+++ b/docs/data/date-pickers/custom-field/custom-field.md
@@ -10,6 +10,10 @@ components: PickersSectionList, PickersTextField
The Date and Time Pickers let you customize the field by passing props or custom components
+:::success
+See [Common concepts—Custom slots and subcomponents](/x/common-concepts/custom-components/) to learn how to use slots.
+:::
+
## Customize the default field
### Customize the `TextField`
diff --git a/docs/data/date-pickers/custom-layout/custom-layout.md b/docs/data/date-pickers/custom-layout/custom-layout.md
index 7a26bee7a059..421e80851236 100644
--- a/docs/data/date-pickers/custom-layout/custom-layout.md
+++ b/docs/data/date-pickers/custom-layout/custom-layout.md
@@ -10,6 +10,10 @@ packageName: '@mui/x-date-pickers'
The Date and Time Pickers let you reorganize the layout
+:::success
+See [Common concepts—Custom slots and subcomponents](/x/common-concepts/custom-components/) to learn how to use slots.
+:::
+
## Default layout structure
By default, pickers are made of 5 subcomponents present in the following order:
diff --git a/docs/data/date-pickers/custom-opening-button/custom-opening-button.md b/docs/data/date-pickers/custom-opening-button/custom-opening-button.md
index 4dadc61d97e0..2e71fe686d5b 100644
--- a/docs/data/date-pickers/custom-opening-button/custom-opening-button.md
+++ b/docs/data/date-pickers/custom-opening-button/custom-opening-button.md
@@ -7,6 +7,10 @@ title: Date and Time Pickers - Custom opening button
The date picker lets you customize the button to open the views.
+:::success
+See [Common concepts—Custom slots and subcomponents](/x/common-concepts/custom-components/) to learn how to use slots.
+:::
+
## Set a custom opening icon
If you want to change the icon opening the picker without changing its behavior, you can use the `openPickerIcon` slot:
diff --git a/docs/data/pages.ts b/docs/data/pages.ts
index dfa4c550422e..68a022f3d6aa 100644
--- a/docs/data/pages.ts
+++ b/docs/data/pages.ts
@@ -12,7 +12,6 @@ const pages: MuiPage[] = [
{
pathname: '/x/introduction-group',
title: 'Introduction',
-
children: [
{ pathname: `/x/introduction`, title: 'Overview' },
{ pathname: `/x/introduction/installation` },
@@ -21,6 +20,13 @@ const pages: MuiPage[] = [
{ pathname: `/x/introduction/roadmap` },
],
},
+ {
+ pathname: '/x/common-features-group',
+ title: 'Common concepts',
+ children: [
+ { pathname: `/x/common-concepts/custom-components`, title: 'Custom slots and subcomponents' },
+ ],
+ },
{
pathname: '/x/react-data-grid-group',
title: 'Data Grid',
@@ -88,7 +94,7 @@ const pages: MuiPage[] = [
{ pathname: '/x/react-data-grid/export' },
{ pathname: '/x/react-data-grid/clipboard', title: 'Copy and paste', newFeature: true },
{ pathname: '/x/react-data-grid/overlays', title: 'Overlays' },
- { pathname: '/x/react-data-grid/components', title: 'Custom subcomponents' },
+ { pathname: '/x/react-data-grid/components', title: 'Custom slots and subcomponents' },
{
pathname: '/x/react-data-grid/style-group',
title: 'Style',
diff --git a/docs/data/tree-view/rich-tree-view/customization/customization.md b/docs/data/tree-view/rich-tree-view/customization/customization.md
index 4bedda31d764..d8172900c158 100644
--- a/docs/data/tree-view/rich-tree-view/customization/customization.md
+++ b/docs/data/tree-view/rich-tree-view/customization/customization.md
@@ -11,6 +11,10 @@ waiAria: https://www.w3.org/WAI/ARIA/apg/patterns/treeview/
Learn how to customize the Rich Tree View component.
+:::success
+See [Common concepts—Custom slots and subcomponents](/x/common-concepts/custom-components/) to learn how to use slots.
+:::
+
## Basics
### Custom icons
diff --git a/docs/data/tree-view/simple-tree-view/customization/customization.md b/docs/data/tree-view/simple-tree-view/customization/customization.md
index 7cf009836436..3774ec10f6ea 100644
--- a/docs/data/tree-view/simple-tree-view/customization/customization.md
+++ b/docs/data/tree-view/simple-tree-view/customization/customization.md
@@ -11,6 +11,10 @@ waiAria: https://www.w3.org/WAI/ARIA/apg/patterns/treeview/
Learn how to customize the Simple Tree View component.