diff --git a/docs/data/date-pickers/base-concepts/base-concepts.md b/docs/data/date-pickers/base-concepts/base-concepts.md
index cf175fda55da..636aa7f934ca 100644
--- a/docs/data/date-pickers/base-concepts/base-concepts.md
+++ b/docs/data/date-pickers/base-concepts/base-concepts.md
@@ -29,6 +29,51 @@ import { DatePicker } from '@mui/x-date-pickers';
import { DatePicker } from '@mui/x-date-pickers-pro';
```
+## Date library
+
+The Date and Time Pickers are focused on UI/UX and, like most other picker components available, require a third-party library to format, parse, and mutate dates.
+
+MUI's components let you choose which library you prefer for this purpose.
+This gives you the flexibility to implement any date library you may already be using in your application, without adding an extra one to your bundle.
+
+To achieve this, both `@mui/x-date-pickers` and `@mui/x-date-pickers-pro` export a set of **adapters** that expose the date manipulation libraries under a unified API.
+
+### Available libraries
+
+The Date and Time Pickers currently support the following date libraries:
+
+- [Day.js](https://day.js.org/)
+- [date-fns](https://date-fns.org/)
+- [Luxon](https://moment.github.io/luxon/#/)
+- [Moment.js](https://momentjs.com/)
+
+:::info
+If you are using a non-Gregorian calendar (such as Jalali or Hijri), please refer to the [Support for other calendar systems](/x/react-date-pickers/calendar-systems/) page.
+:::
+
+### Recommended library
+
+If you are already using one of the libraries listed above in your application, then you can keep using it with the Date and Time Pickers as well.
+This will avoid bundling two libraries.
+
+If you don't have your own requirements or don't manipulate dates outside of MUI X components, then the recommendation is to use `dayjs` because it has the smallest impact on your application's bundle size.
+
+Here is the weight added to your gzipped bundle size by each of these libraries when used inside the Date and Time Pickers:
+
+| Library | Gzipped size |
+| :---------------- | -----------: |
+| `dayjs@1.11.5` | 6.77 kB |
+| `date-fns@2.29.3` | 19.39 kB |
+| `luxon@3.0.4` | 23.26 kB |
+| `moment@2.29.4` | 20.78 kB |
+
+:::info
+The results above were obtained in October 2022 with the latest version of each library.
+The bundling of the JavaScript modules was done by a Create React App, and no locale was loaded for any of the libraries.
+
+The results may vary in your application depending on the version of each library, the locale, and the bundler used.
+:::
+
## Other components
### Choose interaction style
diff --git a/docs/data/date-pickers/getting-started/getting-started.md b/docs/data/date-pickers/getting-started/getting-started.md
index 7572576f22f6..d47244fe608f 100644
--- a/docs/data/date-pickers/getting-started/getting-started.md
+++ b/docs/data/date-pickers/getting-started/getting-started.md
@@ -24,7 +24,7 @@ Using your favorite package manager, install:
:::info
If you need more information about the date library supported by the Date and Time Pickers,
-take a look at the [dedicated section](/x/react-date-pickers/#date-library)
+take a look at the [dedicated section](/x/react-date-pickers/base-concepts/#date-library)
:::
The Date and Time Pickers package has a peer dependency on `@mui/material`.
diff --git a/docs/data/date-pickers/overview/CommonlyUsedComponents.js b/docs/data/date-pickers/overview/CommonlyUsedComponents.js
deleted file mode 100644
index b1ddcc788f64..000000000000
--- a/docs/data/date-pickers/overview/CommonlyUsedComponents.js
+++ /dev/null
@@ -1,112 +0,0 @@
-import * as React from 'react';
-import { styled } from '@mui/material/styles';
-import Tooltip from '@mui/material/Tooltip';
-import Stack from '@mui/material/Stack';
-import { DemoContainer, DemoItem } from '@mui/x-date-pickers/internals/demo';
-import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
-import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
-import { DatePicker } from '@mui/x-date-pickers/DatePicker';
-import { TimePicker } from '@mui/x-date-pickers/TimePicker';
-import { DateTimePicker } from '@mui/x-date-pickers/DateTimePicker';
-import { DateRangePicker } from '@mui/x-date-pickers-pro/DateRangePicker';
-import { DateTimeRangePicker } from '@mui/x-date-pickers-pro/DateTimeRangePicker';
-
-const ProSpan = styled('span')({
- display: 'inline-block',
- height: '1em',
- width: '1em',
- verticalAlign: 'middle',
- marginLeft: '0.3em',
- marginBottom: '0.08em',
- backgroundSize: 'contain',
- backgroundRepeat: 'no-repeat',
- backgroundImage: 'url(https://mui.com/static/x/pro.svg)',
-});
-
-function Label({ componentName, valueType, isProOnly }) {
- const content = (
-
- {componentName} for {valueType} editing
-
- );
-
- if (isProOnly) {
- return (
-
-
-
-
-
-
- {content}
-
- );
- }
-
- return content;
-}
-
-export default function CommonlyUsedComponents() {
- return (
-
-
- }>
-
-
- }>
-
-
- }
- >
-
-
-
- }
- component="DateRangePicker"
- >
-
-
-
- }
- component="DateTimeRangePicker"
- >
-
-
-
-
- );
-}
diff --git a/docs/data/date-pickers/overview/CommonlyUsedComponents.tsx b/docs/data/date-pickers/overview/CommonlyUsedComponents.tsx
deleted file mode 100644
index 81fe975bc477..000000000000
--- a/docs/data/date-pickers/overview/CommonlyUsedComponents.tsx
+++ /dev/null
@@ -1,120 +0,0 @@
-import * as React from 'react';
-import { styled } from '@mui/material/styles';
-import Tooltip from '@mui/material/Tooltip';
-import Stack from '@mui/material/Stack';
-import { DemoContainer, DemoItem } from '@mui/x-date-pickers/internals/demo';
-import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
-import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
-import { DatePicker } from '@mui/x-date-pickers/DatePicker';
-import { TimePicker } from '@mui/x-date-pickers/TimePicker';
-import { DateTimePicker } from '@mui/x-date-pickers/DateTimePicker';
-import { DateRangePicker } from '@mui/x-date-pickers-pro/DateRangePicker';
-import { DateTimeRangePicker } from '@mui/x-date-pickers-pro/DateTimeRangePicker';
-
-const ProSpan = styled('span')({
- display: 'inline-block',
- height: '1em',
- width: '1em',
- verticalAlign: 'middle',
- marginLeft: '0.3em',
- marginBottom: '0.08em',
- backgroundSize: 'contain',
- backgroundRepeat: 'no-repeat',
- backgroundImage: 'url(https://mui.com/static/x/pro.svg)',
-});
-
-function Label({
- componentName,
- valueType,
- isProOnly,
-}: {
- componentName: string;
- valueType: string;
- isProOnly?: boolean;
-}) {
- const content = (
-
- {componentName} for {valueType} editing
-
- );
-
- if (isProOnly) {
- return (
-
-
-
-
-
-
- {content}
-
- );
- }
-
- return content;
-}
-
-export default function CommonlyUsedComponents() {
- return (
-
-
- }>
-
-
- }>
-
-
- }
- >
-
-
-
- }
- component="DateRangePicker"
- >
-
-
-
- }
- component="DateTimeRangePicker"
- >
-
-
-
-
- );
-}
diff --git a/docs/data/date-pickers/overview/overview.md b/docs/data/date-pickers/overview/overview.md
index 8c73477e1a0a..f3cd40be4bc7 100644
--- a/docs/data/date-pickers/overview/overview.md
+++ b/docs/data/date-pickers/overview/overview.md
@@ -7,68 +7,16 @@ materialDesign: https://m2.material.io/components/date-pickers
waiAria: https://www.w3.org/WAI/ARIA/apg/patterns/dialog-modal/examples/datepicker-dialog/
---
-# MUI X Date and Time Pickers
-
-
These react date picker and time picker components let users select date or time values.
-
-{{"component": "@mui/docs/ComponentLinkHeader"}}
-
-## Overview
-
-{{"demo": "CommonlyUsedComponents.js"}}
-
-## Community or Pro plan?
-
-The Date and Time Pickers are available in two packages:
-
-- `@mui/x-date-pickers`, which is MIT licensed (free forever) and contains all the components to edit a date and/or a time.
-- `@mui/x-date-pickers-pro`, which is [commercially licensed](/x/introduction/licensing/#pro-plan) and contains additional components to edit date and/or time ranges.
-
-## Date library
-
-The Date and Time Pickers are focused on UI/UX and, like most other picker components available, require a third-party library to format, parse, and mutate dates.
-
-MUI's components let you choose which library you prefer for this purpose.
-This gives you the flexibility to implement any date library you may already be using in your application, without adding an extra one to your bundle.
+{{"component": "modules/components/overview/XLogo.tsx"}}
-To achieve this, both `@mui/x-date-pickers` and `@mui/x-date-pickers-pro` export a set of **adapters** that expose the date manipulation libraries under a unified API.
-
-### Available libraries
-
-The Date and Time Pickers currently support the following date libraries:
-
-- [Day.js](https://day.js.org/)
-- [date-fns](https://date-fns.org/)
-- [Luxon](https://moment.github.io/luxon/#/)
-- [Moment.js](https://momentjs.com/)
-
-:::info
-If you are using a non-Gregorian calendar (such as Jalali or Hijri), please refer to the [Support for other calendar systems](/x/react-date-pickers/calendar-systems/) page.
-:::
-
-### Recommended library
-
-If you are already using one of the libraries listed above in your application, then you can keep using it with the Date and Time Pickers as well.
-This will avoid bundling two libraries.
-
-If you don't have your own requirements or don't manipulate dates outside of MUI X components, then the recommendation is to use `dayjs` because it has the smallest impact on your application's bundle size.
-
-Here is the weight added to your gzipped bundle size by each of these libraries when used inside the Date and Time Pickers:
-
-| Library | Gzipped size |
-| :---------------- | -----------: |
-| `dayjs@1.11.5` | 6.77 kB |
-| `date-fns@2.29.3` | 19.39 kB |
-| `luxon@3.0.4` | 23.26 kB |
-| `moment@2.29.4` | 20.78 kB |
-
-:::info
-The results above were obtained in October 2022 with the latest version of each library.
-The bundling of the JavaScript modules was done by a Create React App, and no locale was loaded for any of the libraries.
+# MUI X Date and Time Pickers
-The results may vary in your application depending on the version of each library, the locale, and the bundler used.
-:::
+A collection of React UI components for selecting dates, times, and ranges.
-## What's next?
+{{"component": "modules/components/overview/MainDemo.tsx"}}
-Continue to the [next page](/x/react-date-pickers/getting-started/) and learn how to prepare your application for the Date and Time Pickers.
+{{"component": "modules/components/overview/FeatureHighlight.tsx"}}
+{{"component": "modules/components/overview/CommunityOrPro.tsx"}}
+{{"component": "modules/components/overview/Keyboard.tsx"}}
+{{"component": "modules/components/overview/Internationalization.tsx"}}
+{{"component": "modules/components/overview/DateLibraries.tsx"}}
diff --git a/docs/pages/x/react-date-pickers/index.js b/docs/pages/x/react-date-pickers/index.js
index b3933fe81dc2..204ca09b82db 100644
--- a/docs/pages/x/react-date-pickers/index.js
+++ b/docs/pages/x/react-date-pickers/index.js
@@ -3,5 +3,5 @@ import MarkdownDocs from 'docs/src/modules/components/MarkdownDocs';
import * as pageProps from 'docsx/data/date-pickers/overview/overview.md?muiMarkdown';
export default function Page() {
- return ;
+ return ;
}
diff --git a/docs/public/static/x/date-libraries/datefns.png b/docs/public/static/x/date-libraries/datefns.png
new file mode 100644
index 000000000000..ab1beba7507e
Binary files /dev/null and b/docs/public/static/x/date-libraries/datefns.png differ
diff --git a/docs/public/static/x/date-libraries/dayjs.png b/docs/public/static/x/date-libraries/dayjs.png
new file mode 100644
index 000000000000..1eb9630fbee3
Binary files /dev/null and b/docs/public/static/x/date-libraries/dayjs.png differ
diff --git a/docs/public/static/x/date-libraries/luxon.png b/docs/public/static/x/date-libraries/luxon.png
new file mode 100644
index 000000000000..41e6bc0d5766
Binary files /dev/null and b/docs/public/static/x/date-libraries/luxon.png differ
diff --git a/docs/public/static/x/date-libraries/momentjs.png b/docs/public/static/x/date-libraries/momentjs.png
new file mode 100644
index 000000000000..32d3732df27c
Binary files /dev/null and b/docs/public/static/x/date-libraries/momentjs.png differ
diff --git a/docs/src/modules/components/overview/CommunityOrPro.tsx b/docs/src/modules/components/overview/CommunityOrPro.tsx
new file mode 100644
index 000000000000..7e6dcbf3de21
--- /dev/null
+++ b/docs/src/modules/components/overview/CommunityOrPro.tsx
@@ -0,0 +1,81 @@
+import * as React from 'react';
+import Box from '@mui/material/Box';
+import Button from '@mui/material/Button';
+import Divider from '@mui/material/Divider';
+import Stack from '@mui/material/Stack';
+import Typography from '@mui/material/Typography';
+import ArrowForwardIcon from '@mui/icons-material/ArrowForward';
+import InfoCard from './InfoCard';
+
+export default function CommunityOrPro() {
+ return (
+
+
+
+
+
+
+ Community and Pro
+
+
+ Two packages for every need
+
+
+ Start with the free-forever Community version, then upgrade to Pro when you are ready
+ for additional features and components.
+
+
+
+ }
+ sx={{ width: 'fit-content' }}
+ >
+ About licensing
+
+
+
+
+ }
+ description={[
+ 'Free forever under an MIT license. Includes Date Pickers, Time Pickers, and Date Time Pickers.',
+ ]}
+ backgroundColor="subtle"
+ link="/pricing"
+ />
+
+
+ }
+ description={[
+ 'Requires a commercial license. Includes all Community components plus the Date and Time Range Pickers.',
+ ]}
+ backgroundColor="subtle"
+ link="/pricing"
+ />
+
+
+
+
+ );
+}
diff --git a/docs/src/modules/components/overview/DateLibraries.tsx b/docs/src/modules/components/overview/DateLibraries.tsx
new file mode 100644
index 000000000000..139365eac622
--- /dev/null
+++ b/docs/src/modules/components/overview/DateLibraries.tsx
@@ -0,0 +1,114 @@
+import * as React from 'react';
+// @ts-ignore
+import SectionHeadline from 'docs/src/components/typography/SectionHeadline';
+import { HighlightedCode } from '@mui/docs/HighlightedCode';
+import Box from '@mui/material/Box';
+import Button from '@mui/material/Button';
+import Divider from '@mui/material/Divider';
+import Stack from '@mui/material/Stack';
+import ToggleButtonGroup from '@mui/material/ToggleButtonGroup';
+import ToggleButton from '@mui/material/ToggleButton';
+import Typography from '@mui/material/Typography';
+import ArrowForwardIcon from '@mui/icons-material/ArrowForward';
+
+const dateLibraries = [
+ {
+ name: 'Dayjs',
+ link: '/static/x/date-libraries/dayjs.png',
+ adapter: 'AdapterDayjs',
+ value: "dayjs('2024-04-17')",
+ },
+ {
+ name: 'Luxon',
+ link: '/static/x/date-libraries/luxon.png',
+ adapter: 'AdapterLuxon',
+ value: "DateTime.fromISO('2024-04-17')",
+ },
+ {
+ name: 'date-fns',
+ link: '/static/x/date-libraries/datefns.png',
+ adapter: 'AdapterDateFns',
+ value: "new Date('2024-04-17')",
+ },
+ {
+ name: 'Moment.js',
+ link: '/static/x/date-libraries/momentjs.png',
+ adapter: 'AdapterMoment',
+ value: "moment('2024-04-17')",
+ },
+];
+
+export default function DateLibraries() {
+ const [selectedLibrary, setSelectedLibrary] = React.useState(0);
+
+ const handleLibrarySwitch = (_event: React.MouseEvent, library: number) => {
+ if (library !== null) {
+ setSelectedLibrary(library);
+ }
+ };
+ return (
+
+
+
+
+
+ Use your favorite date library
+
+ }
+ description="MUI X Date Pickers integrate smoothly with the most popular date libraries available."
+ />
+
+
+
+
+ {dateLibraries.map((library, index) => (
+
+
+ {library.name}
+
+ ))}
+
+
+ }
+ >
+ More info
+
+
+ `,
+ ` `,
+ ``,
+ ].join('\n')}
+ language="jsx"
+ copyButtonHidden
+ />
+
+
+
+
+ );
+}
diff --git a/docs/src/modules/components/overview/FeatureHighlight.tsx b/docs/src/modules/components/overview/FeatureHighlight.tsx
new file mode 100644
index 000000000000..684d7972340e
--- /dev/null
+++ b/docs/src/modules/components/overview/FeatureHighlight.tsx
@@ -0,0 +1,72 @@
+import * as React from 'react';
+import Divider from '@mui/material/Divider';
+import Typography from '@mui/material/Typography';
+import Stack from '@mui/material/Stack';
+import FormatPaintIcon from '@mui/icons-material/FormatPaint';
+import AccessibilityNewIcon from '@mui/icons-material/AccessibilityNew';
+import LanguageIcon from '@mui/icons-material/Language';
+import InfoCard from './InfoCard';
+
+const featuredItems = [
+ {
+ title: 'Highly customizable',
+ description:
+ 'Start with our meticulous Material Design implementation, or go fully custom with your own design system.',
+ icon: ,
+ },
+ {
+ title: 'Accessibility',
+ description:
+ 'We are committed to meeting or exceeding global standards for accessibility, and we provide thorough guidance on best practices in our documentation.',
+ icon: ,
+ },
+ {
+ title: 'Internationalization',
+ description:
+ 'Serve the needs of users all around the world with built-in support for multiple time zones, languages, and date formats.',
+ icon: ,
+ },
+];
+
+export default function FeatureHighlight() {
+ return (
+
+
+
+
+
+ Using MUI X Date Pickers
+
+
+ First-class developer experience
+
+
+ MUI X Date and Time Pickers are designed to be delightful and intuitive for developers
+ and users alike.
+
+
+
+ {featuredItems.map(({ title, description, icon }, index) => (
+
+ ))}
+
+
+
+ );
+}
diff --git a/docs/src/modules/components/overview/InfoCard.tsx b/docs/src/modules/components/overview/InfoCard.tsx
new file mode 100644
index 000000000000..aaaebb419a61
--- /dev/null
+++ b/docs/src/modules/components/overview/InfoCard.tsx
@@ -0,0 +1,107 @@
+import * as React from 'react';
+import { alpha } from '@mui/material/styles';
+import Link from '@mui/material/Link';
+import Typography from '@mui/material/Typography';
+import Stack from '@mui/material/Stack';
+import Paper from '@mui/material/Paper';
+
+type InfoCardProps = {
+ title: string;
+ description?: string | string[];
+ icon?: React.ReactNode;
+ onClick?: () => void;
+ active?: boolean;
+ backgroundColor?: 'gradient' | 'subtle';
+ link?: string;
+};
+export default function InfoCard({
+ title,
+ description,
+ icon: Icon,
+ onClick,
+ active,
+ backgroundColor = 'gradient',
+ link,
+}: InfoCardProps) {
+ const clickable = Boolean(onClick);
+
+ return (
+ ({
+ p: 2.5,
+ display: 'flex',
+ flexDirection: 'column',
+ justifyContent: 'center',
+ textAlign: 'left',
+ flexGrow: 1,
+ height: '100%',
+ boxShadow: 'transparent',
+ background:
+ backgroundColor === 'gradient'
+ ? `${(theme.vars || theme).palette.gradients.linearSubtle}`
+ : 'transparent',
+ ...(clickable && {
+ cursor: 'pointer',
+ '&:hover': {
+ opacity: 1,
+ boxShadow: `0px 2px 30px 0px ${alpha(theme.palette.primary[50], 0.3)} inset, 0px 1px 6px 0px ${theme.palette.primary[100]}`,
+ borderColor: 'primary.100',
+ ...(active && {
+ borderColor: 'primary.300',
+ }),
+ },
+ ...(active && {
+ boxShadow: `0px 2px 30px 0px ${alpha(theme.palette.primary[50], 0.3)} inset, 0px 1px 6px 0px ${theme.palette.primary[100]}`,
+ borderColor: 'primary.200',
+ }),
+ ...(!active && { borderColor: 'grey.300', opacity: 0.7 }),
+ }),
+ ...theme.applyDarkStyles({
+ bgcolor: alpha(theme.palette.primaryDark[800], 0.25),
+ background: `${(theme.vars || theme).palette.gradients.linearSubtle}`,
+ borderColor: 'primaryDark.700',
+ ...(clickable && {
+ '&:hover': {
+ boxShadow: `0px 2px 30px 0px ${alpha(theme.palette.primary[800], 0.1)} inset, 0px 1px 6px 0px ${theme.palette.primary[900]}`,
+
+ borderColor: 'primary.300',
+ },
+ ...(active && {
+ boxShadow: `0px 2px 30px 0px ${alpha(theme.palette.primary[800], 0.1)} inset, 0px 1px 6px 0px ${theme.palette.primary[900]}`,
+ borderColor: 'primary.100',
+ }),
+ }),
+ }),
+ })}
+ >
+
+ {Icon}
+
+ {title}
+
+
+ {description && typeof description === 'string' && (
+
+ {description}
+
+ )}
+ {description &&
+ typeof description === 'object' &&
+ description.map((item, index) => (
+
+ {item}
+
+ ))}
+
+ );
+}
diff --git a/docs/src/modules/components/overview/Internationalization.tsx b/docs/src/modules/components/overview/Internationalization.tsx
new file mode 100644
index 000000000000..5f5353a4e952
--- /dev/null
+++ b/docs/src/modules/components/overview/Internationalization.tsx
@@ -0,0 +1,387 @@
+import * as React from 'react';
+import dayjs from 'dayjs';
+import 'dayjs/locale/ro';
+import 'dayjs/locale/zh-cn';
+import utc from 'dayjs/plugin/utc';
+import timezone from 'dayjs/plugin/timezone';
+import { styled, createTheme, ThemeProvider, useTheme } from '@mui/material/styles';
+// @ts-ignore
+import SectionHeadline from 'docs/src/components/typography/SectionHeadline';
+import Box from '@mui/material/Box';
+import Button from '@mui/material/Button';
+import Divider from '@mui/material/Divider';
+import Paper from '@mui/material/Paper';
+import Stack from '@mui/material/Stack';
+import MuiToggleButtonGroup, { toggleButtonGroupClasses } from '@mui/material/ToggleButtonGroup';
+import MuiToggleButton from '@mui/material/ToggleButton';
+import Typography from '@mui/material/Typography';
+import ArrowForwardIcon from '@mui/icons-material/ArrowForward';
+import {
+ DateTimeRangePicker,
+ DateTimeField,
+ DatePicker,
+ DateTimeValidationError,
+ DateCalendar,
+} from '@mui/x-date-pickers-pro';
+import { AdapterDayjs } from '@mui/x-date-pickers-pro/AdapterDayjs';
+import { LocalizationProvider } from '@mui/x-date-pickers-pro/LocalizationProvider';
+import { roRO, enUS, zhCN } from '@mui/x-date-pickers-pro/locales';
+import InfoCard from './InfoCard';
+import WorldMapSvg, { ContinentClickHandler } from './WorldMapSvg';
+
+dayjs.extend(utc);
+dayjs.extend(timezone);
+
+const internationalizationFeatures = [
+ {
+ title: 'Support for multiple timezones',
+ description: 'Accommodate global users and events in any geographical location.',
+ },
+ {
+ title: 'Support for multiple languages',
+ description:
+ "Meet users where they're at with support for common date formats and languages used around the world.",
+ },
+ {
+ title: 'Validation and error handling',
+ description: 'We have all use cases covered for you and your end users.',
+ },
+];
+
+function DemoWrapper({
+ children,
+ controls: ToolbarControls,
+ link,
+}: {
+ children: React.ReactNode;
+ controls?: React.ReactNode;
+ link: string;
+}) {
+ return (
+ ({
+ display: 'flex',
+ flexDirection: 'column',
+ alignItems: 'center',
+ border: '1px solid',
+ borderColor: 'divider',
+ borderRadius: 1,
+ flexGrow: 1,
+ width: '100%',
+ justifyContent: 'space-between',
+ background: (brandingTheme.vars || brandingTheme).palette.gradients.linearSubtle,
+ })}
+ >
+ {children}
+
+ ({
+ width: '100%',
+ border: '1px solid transparent',
+ borderTopColor: 'divider',
+ borderTopLeftRadius: 0,
+ borderTopRightRadius: 0,
+ display: 'flex',
+ padding: brandingTheme.spacing(1),
+ justifyContent: 'flex-end',
+ alignItems: { md: 'center' },
+ gap: 2,
+ })}
+ >
+ {ToolbarControls}
+ }>
+ More info
+
+
+
+ );
+}
+
+function TimezonesDemo() {
+ const [selectedTimezone, setSelectedTimezone] = React.useState(null);
+ const brandingTheme = useTheme();
+ const theme = createTheme({ palette: { mode: brandingTheme.palette.mode } });
+
+ const handleContinentClick: ContinentClickHandler = (e, newTimezone) => {
+ if (selectedTimezone === newTimezone) {
+ setSelectedTimezone(null);
+ } else {
+ setSelectedTimezone(newTimezone);
+ }
+ };
+
+ return (
+
+
+
+
+ {selectedTimezone ? `Selected timezone: ${selectedTimezone}` : 'Select timezone'}
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
+
+type Languages = 'en' | 'ro' | 'zh-cn';
+const locales = {
+ ro: roRO,
+ en: enUS,
+ 'zh-cn': zhCN,
+};
+
+const ToggleButton = styled(MuiToggleButton)({
+ borderColor: 'transparent',
+ padding: '5px 8px',
+});
+const ToggleButtonGroup = styled(MuiToggleButtonGroup)(({ theme }) => ({
+ gap: theme.spacing(1),
+ [`& .${toggleButtonGroupClasses.firstButton}, & .${toggleButtonGroupClasses.lastButton},& .${toggleButtonGroupClasses.middleButton} `]:
+ {
+ borderRadius: theme.shape.borderRadius,
+ },
+}));
+
+function Controls({
+ selectedLanguage,
+ handleLanguageSwitch,
+}: {
+ selectedLanguage: Languages;
+ handleLanguageSwitch: (event: React.MouseEvent, newLanguage: Languages) => void;
+}) {
+ return (
+
+
+
+ Română
+
+
+ English
+
+
+ 日本語
+
+
+
+ );
+}
+
+function LanguagesDemo() {
+ const brandingTheme = useTheme();
+ const [selectedLanguage, setSelectedLanguage] = React.useState('zh-cn');
+
+ const theme = createTheme({ palette: { mode: brandingTheme.palette.mode } });
+
+ const handleLanguageSwitch = (_event: React.MouseEvent, newLanguage: Languages) => {
+ if (newLanguage !== null) {
+ setSelectedLanguage(newLanguage);
+ }
+ };
+
+ return (
+
+
+ }
+ link="/x/react-date-pickers/localization"
+ >
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
+
+const startOfQ12022 = dayjs('2024-01-01T00:00:00.000');
+const endOfQ12022 = dayjs('2024-03-31T23:59:59.999');
+const fiveAM = dayjs().set('hour', 5).startOf('hour');
+const nineAM = dayjs().set('hour', 9).startOf('hour');
+
+const getError = (error: DateTimeValidationError | null) => {
+ switch (error) {
+ case 'maxDate':
+ case 'minDate': {
+ return 'Please select a date in the first quarter of 2024';
+ }
+
+ case 'invalidDate': {
+ return 'Your date is not valid';
+ }
+
+ default: {
+ return '';
+ }
+ }
+};
+
+function ValidationDemo() {
+ const brandingTheme = useTheme();
+ const [fieldError, setFieldError] = React.useState(null);
+ const [pickerError, setPickerError] = React.useState(null);
+
+ const theme = createTheme({ palette: { mode: brandingTheme.palette.mode } });
+
+ return (
+
+
+
+
+ setFieldError(newError)}
+ slotProps={{
+ textField: {
+ helperText: getError(fieldError),
+ fullWidth: true,
+ },
+ }}
+ minDate={startOfQ12022}
+ maxDate={endOfQ12022}
+ />
+ setPickerError(newError)}
+ slotProps={{
+ textField: {
+ helperText: getError(pickerError),
+ fullWidth: true,
+ },
+ }}
+ minDate={startOfQ12022}
+ maxDate={endOfQ12022}
+ />
+
+
+
+
+
+ );
+}
+
+export default function Internationalization() {
+ const [activeItem, setActiveItem] = React.useState(0);
+
+ return (
+
+
+
+
+
+ {internationalizationFeatures[activeItem].title}
+
+ }
+ />
+ {internationalizationFeatures.map(({ title, description }, index) => (
+ setActiveItem(index)}
+ backgroundColor="subtle"
+ />
+ ))}
+
+
+ {activeItem === 0 && }
+ {activeItem === 1 && }
+ {activeItem === 2 && }
+
+
+
+ );
+}
diff --git a/docs/src/modules/components/overview/Keyboard.tsx b/docs/src/modules/components/overview/Keyboard.tsx
new file mode 100644
index 000000000000..a587bf3f0164
--- /dev/null
+++ b/docs/src/modules/components/overview/Keyboard.tsx
@@ -0,0 +1,503 @@
+import * as React from 'react';
+import clsx from 'clsx';
+import dayjs from 'dayjs';
+// @ts-ignore
+import SectionHeadline from 'docs/src/components/typography/SectionHeadline';
+import Button from '@mui/material/Button';
+import Divider from '@mui/material/Divider';
+import Stack from '@mui/material/Stack';
+import Typography from '@mui/material/Typography';
+import ArrowForwardIcon from '@mui/icons-material/ArrowForward';
+import { styled, alpha, createTheme, ThemeProvider, useTheme } from '@mui/material/styles';
+import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
+import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
+import { DateField } from '@mui/x-date-pickers/DateField';
+import { FieldSelectedSections } from '@mui/x-date-pickers/models';
+
+type KeyType = {
+ label: string;
+ showLabel?: boolean;
+ width?: number;
+ displayedLabel?: string;
+ location?: number;
+ shouldSelect?: boolean;
+ code?: string;
+ keyCode?: number;
+ height?: number;
+ x?: number;
+ y?: number;
+ keyType?: 'navigate-left' | 'navigate-right' | 'input';
+};
+
+const keys: KeyType[][] = [
+ [
+ { label: 'Escape', width: 43, showLabel: true, displayedLabel: 'Esc', shouldSelect: true },
+ { label: 'f1', width: 23, showLabel: false },
+ { label: 'f2', width: 23, showLabel: false },
+ { label: 'f3', width: 23, showLabel: false },
+ { label: 'f4', width: 23, showLabel: false },
+ { label: 'f5', width: 23, showLabel: false },
+ { label: 'f6', width: 23, showLabel: false },
+ { label: 'f7', width: 23, showLabel: false },
+ { label: 'f8', width: 23, showLabel: false },
+ { label: 'f9', width: 23, showLabel: false },
+ { label: 'f10', width: 23, showLabel: false },
+ { label: 'f11', width: 23, showLabel: false },
+ { label: 'f12', width: 23, showLabel: false },
+ { label: 'Delete', width: 23, showLabel: true, shouldSelect: true, displayedLabel: 'Del' },
+ ],
+ [
+ { label: '`', width: 23, showLabel: true },
+ {
+ label: '1',
+ width: 23,
+ showLabel: true,
+ shouldSelect: true,
+ code: 'Digit1',
+ keyCode: 49,
+ keyType: 'input',
+ },
+ {
+ label: '2',
+ width: 23,
+ showLabel: true,
+ shouldSelect: true,
+ code: 'Digit2',
+ keyCode: 50,
+ keyType: 'input',
+ },
+ {
+ label: '3',
+ width: 23,
+ showLabel: true,
+ shouldSelect: true,
+ code: 'Digit3',
+ keyCode: 51,
+ keyType: 'input',
+ },
+ {
+ label: '4',
+ width: 23,
+ showLabel: true,
+ shouldSelect: true,
+ code: 'Digit4',
+ keyCode: 52,
+ keyType: 'input',
+ },
+ {
+ label: '5',
+ width: 23,
+ showLabel: true,
+ shouldSelect: true,
+ code: 'Digit5',
+ keyCode: 53,
+ keyType: 'input',
+ },
+ {
+ label: '6',
+ width: 23,
+ showLabel: true,
+ shouldSelect: true,
+ code: 'Digit6',
+ keyCode: 54,
+ keyType: 'input',
+ },
+ {
+ label: '7',
+ width: 23,
+ showLabel: true,
+ shouldSelect: true,
+ code: 'Digit7',
+ keyCode: 55,
+ keyType: 'input',
+ },
+ {
+ label: '8',
+ width: 23,
+ showLabel: true,
+ shouldSelect: true,
+ code: 'Digit8',
+ keyCode: 56,
+ keyType: 'input',
+ },
+ {
+ label: '9',
+ width: 23,
+ showLabel: true,
+ shouldSelect: true,
+ code: 'Digit9',
+ keyCode: 57,
+ keyType: 'input',
+ },
+ {
+ label: '0',
+ width: 23,
+ showLabel: true,
+ shouldSelect: true,
+ code: 'Digit0',
+ keyCode: 58,
+ keyType: 'input',
+ },
+ { label: '-', width: 23, showLabel: false },
+ { label: '=', width: 23, showLabel: false },
+ {
+ label: 'Backspace',
+ displayedLabel: 'Back',
+ width: 43,
+ showLabel: true,
+ code: 'Backspace',
+ keyCode: 8,
+ shouldSelect: true,
+ },
+ ],
+ [
+ { label: 'Tab', width: 43, showLabel: true, shouldSelect: true },
+ { label: 'q', width: 23, showLabel: false },
+ { label: 'w', width: 23, showLabel: false },
+ { label: 'e', width: 23, showLabel: false },
+ { label: 'r', width: 23, showLabel: false },
+ { label: 't', width: 23, showLabel: false },
+ { label: 'y', width: 23, showLabel: false },
+ { label: 'u', width: 23, showLabel: false },
+ { label: 'i', width: 23, showLabel: false },
+ { label: 'o', width: 23, showLabel: false },
+ { label: 'p', width: 23, showLabel: false },
+ { label: '[', width: 23, showLabel: false },
+ { label: ']', width: 23, showLabel: false },
+ { label: '\\', width: 23, showLabel: false },
+ ],
+ [
+ { label: 'CapsLock', width: 49, showLabel: true, displayedLabel: 'Caps', shouldSelect: true },
+ { label: 'a', width: 23, showLabel: false },
+ { label: 's', width: 23, showLabel: false },
+ { label: 'd', width: 23, showLabel: false },
+ { label: 'f', width: 23, showLabel: false },
+ { label: 'g', width: 23, showLabel: false },
+ { label: 'h', width: 23, showLabel: false },
+ { label: 'j', width: 23, showLabel: false },
+ { label: 'k', width: 23, showLabel: false },
+ { label: 'l', width: 23, showLabel: false },
+ { label: ';', width: 23, showLabel: false },
+ { label: "'", width: 23, showLabel: false },
+ { label: 'Enter', width: 45, showLabel: true, shouldSelect: true },
+ ],
+ [
+ { label: 'Shift', width: 59, showLabel: true, location: 1 },
+ { label: 'z', width: 23, showLabel: false },
+ { label: 'x', width: 23, showLabel: false },
+ { label: 'c', width: 23, showLabel: false },
+ { label: 'v', width: 23, showLabel: false },
+ { label: 'b', width: 23, showLabel: false },
+ { label: 'n', width: 23, showLabel: false },
+ { label: 'm', width: 23, showLabel: false },
+ { label: ',', width: 23, showLabel: false },
+ { label: '.', width: 23, showLabel: false },
+ { label: '/', width: 23, showLabel: true },
+ { label: 'Shift', width: 63, showLabel: true, location: 2 },
+ ],
+ [
+ { label: 'Control', width: 43, showLabel: true, location: 1, displayedLabel: 'Ctrl' },
+ { label: 'Meta', width: 29, showLabel: false },
+ { label: 'Alt', width: 42, showLabel: true, location: 1 },
+ { label: ' ', width: 119, showLabel: false, displayedLabel: 'Space' },
+ { label: 'Alt', width: 42, showLabel: true, location: 2 },
+ { label: 'Control', width: 23, showLabel: true, location: 2, displayedLabel: 'Ctrl' },
+ ],
+];
+
+const arrowKeys: KeyType[] = [
+ {
+ label: 'ArrowLeft',
+ width: 23,
+ height: 9,
+ showLabel: false,
+ shouldSelect: true,
+ x: 340.5,
+ y: 166.5,
+ keyType: 'navigate-left',
+ },
+ {
+ label: 'ArrowUp',
+ width: 23,
+ height: 9,
+ showLabel: false,
+ shouldSelect: true,
+ x: 368.5,
+ y: 152.5,
+ },
+ {
+ label: 'ArrowDown',
+ width: 23,
+ height: 9,
+ showLabel: false,
+ shouldSelect: true,
+ x: 368.5,
+ y: 166.5,
+ },
+ {
+ label: 'ArrowRight',
+ width: 23,
+ height: 9,
+ showLabel: false,
+ shouldSelect: true,
+ x: 396.5,
+ y: 166.5,
+ keyType: 'navigate-right',
+ },
+];
+
+const RootRectangle = styled('rect')(({ theme }) => ({
+ fill: 'white',
+ stroke: theme.palette.grey[500],
+ ...(theme.palette.mode === 'dark' && {
+ stroke: theme.palette.grey[600],
+ fill: theme.palette.background.paper,
+ }),
+}));
+const KeyRoot = styled('g')(({ theme }) => ({
+ cursor: 'pointer',
+ '&:not(.selected):hover ': { '& .key-rect': { fill: theme.palette.action.hover } },
+ '&.selected': { '& .key-rect': { fill: alpha(theme.palette.primary.main, 0.2) } },
+}));
+const KeyRectangle = styled('rect')(({ theme }) => ({
+ fill: 'white',
+ stroke: theme.palette.grey[500],
+ ...(theme.palette.mode === 'dark' && {
+ stroke: theme.palette.grey[600],
+ fill: theme.palette.background.paper,
+ }),
+}));
+const KeyText = styled('text')(({ theme }) => ({
+ fill: theme.palette.grey[800],
+ fontSize: 9,
+ fontFamily: 'IBM Plex Sans',
+ ...(theme.palette.mode === 'dark' && { fill: theme.palette.text.primary }),
+}));
+
+type KeyboardSvgProps = {
+ handleKeySelection: HandleKeySelection;
+ selectedKey: SelectedKey | null;
+};
+
+export function KeyboardSvg({ selectedKey, handleKeySelection }: KeyboardSvgProps) {
+ return (
+
+
+
+
+
+ {keys.map((row, rowIndex) => {
+ let xPosition = 12.5;
+ const yPosition = 12.5 + rowIndex * 28;
+ return (
+
+ {row.map(
+ (
+ {
+ label,
+ displayedLabel,
+ showLabel,
+ width = 23,
+ location = 0,
+ shouldSelect = false,
+ code,
+ keyCode,
+ },
+ keyIndex,
+ ) => {
+ const textXPosition = xPosition + width / 2;
+ const textYPosition = yPosition + 11.5;
+ const keyComponent = (
+ {
+ if (shouldSelect) {
+ e.preventDefault();
+
+ handleKeySelection(e, {
+ key: label,
+ location: location || 0,
+ code: code || label,
+ keyCode: keyCode || 0,
+ });
+ }
+ }}
+ onMouseUp={(e) => {
+ if (shouldSelect) {
+ handleKeySelection(e, null);
+ }
+ }}
+ >
+
+ {showLabel && (
+
+ {displayedLabel || label}
+
+ )}
+
+ );
+ xPosition = xPosition + width + 5;
+
+ return keyComponent;
+ },
+ )}
+
+ );
+ })}
+ {arrowKeys.map(
+ ({ label: key, location = 0, code = key, keyCode, width, height, x, y }, keyIndex) => {
+ return (
+ {
+ e.preventDefault();
+ handleKeySelection(e, { key, location, code, keyCode });
+ }}
+ onMouseUp={(e) => {
+ handleKeySelection(e, null);
+ }}
+ >
+
+
+ );
+ },
+ )}
+
+ );
+}
+
+type SelectedKey = {
+ key: string;
+ location?: number;
+ code?: string;
+ keyCode?: number;
+};
+type HandleKeySelection = (e: React.SyntheticEvent, key: SelectedKey | null) => void;
+
+export default function Keyboard() {
+ const [selectedKey, setSelectedKey] = React.useState(null);
+ const ref = React.useRef(null);
+ const selectedSection = React.useRef(0);
+
+ const brandingTheme = useTheme();
+ const theme = createTheme({ palette: { mode: brandingTheme.palette.mode } });
+
+ const handleKeySelection = (e: React.SyntheticEvent, key: SelectedKey | null) => {
+ const sectionContent = (ref.current as any).querySelector(
+ `.MuiPickersSectionList-section[data-sectionindex="${selectedSection.current || 0}"] .MuiPickersSectionList-sectionContent`,
+ );
+ sectionContent.focus();
+
+ if (key) {
+ const event = new KeyboardEvent('keydown', {
+ ...key,
+ bubbles: true,
+ cancelable: true,
+ });
+
+ sectionContent.dispatchEvent(event);
+
+ if (key.key === 'Backspace') {
+ sectionContent.textContent = '';
+ const inputEvent = new InputEvent('input', {
+ data: '',
+ inputType: 'insertText',
+ bubbles: true,
+ cancelable: true,
+ });
+
+ sectionContent.dispatchEvent(inputEvent);
+ } else if (key?.keyCode && key?.keyCode >= 49 && key?.keyCode <= 58) {
+ sectionContent.textContent = key.key;
+ const inputEvent = new InputEvent('input', {
+ data: key.key,
+ inputType: 'insertText',
+ bubbles: true,
+ cancelable: true,
+ });
+ sectionContent.dispatchEvent(inputEvent);
+ }
+ }
+ setSelectedKey(key);
+ };
+
+ return (
+
+
+
+
+
+ Assistive technology support
+
+ }
+ description="The MUI X Date Pickers feature advanced keyboard support that's compliant with WCAG and WAI-ARIA standards, so users who require assistive technology can navigate your interface with ease."
+ />
+
+ }
+ sx={{ width: 'fit-content' }}
+ >
+ More info
+
+
+
+
+ {
+ setSelectedKey({
+ key: e.key,
+ code: e.code,
+ location: e.location,
+ });
+ }}
+ onKeyUp={() => {
+ setSelectedKey(null);
+ }}
+ enableAccessibleFieldDOMStructure
+ onSelectedSectionsChange={(newSelectedSection) => {
+ selectedSection.current = newSelectedSection;
+ }}
+ />
+
+
+
+
+
+ );
+}
diff --git a/docs/src/modules/components/overview/MainDemo.tsx b/docs/src/modules/components/overview/MainDemo.tsx
new file mode 100644
index 000000000000..279e80189673
--- /dev/null
+++ b/docs/src/modules/components/overview/MainDemo.tsx
@@ -0,0 +1,125 @@
+import * as React from 'react';
+import { useTheme, ThemeProvider, createTheme, Theme, Components } from '@mui/material/styles';
+import useMediaQuery from '@mui/material/useMediaQuery';
+import Stack from '@mui/material/Stack';
+import Paper from '@mui/material/Paper';
+import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
+import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
+import FlightPicker from './mainDemo/FlightPicker';
+import ThemeToggleGroup from './mainDemo/ThemeToggleGroup';
+import Clock from './mainDemo/Clock';
+import Birthday from './mainDemo/Birthday';
+import DigitalClock from './mainDemo/DigitalClock';
+import DateRangeWithShortcuts from './mainDemo/DateRangeWithShortcuts';
+import PickerButton from './mainDemo/PickerButton';
+import '@mui/x-date-pickers-pro/themeAugmentation';
+
+const components: Components = {
+ MuiPickersDay: {
+ styleOverrides: {
+ root: {
+ fontWeight: 400,
+ },
+ today: ({ theme }) => ({
+ fontWeight: 600,
+ borderColor: theme.palette.primary.light,
+ }),
+ },
+ },
+ MuiPickersMonth: {
+ styleOverrides: {
+ monthButton: ({ theme }) => ({
+ fontWeight: 400,
+ fontSize: '0.875rem',
+ borderRadius: theme.shape.borderRadius,
+ height: 28,
+ width: 64,
+ }),
+ },
+ },
+ MuiPickersYear: {
+ styleOverrides: {
+ yearButton: ({ theme }) => ({
+ fontWeight: 400,
+ fontSize: '0.875rem',
+ borderRadius: theme.shape.borderRadius,
+ height: 28,
+ width: 64,
+ }),
+ },
+ },
+ MuiPickersToolbar: { styleOverrides: { content: { justifyContent: 'space-between' } } },
+ MuiTimePickerToolbar: {
+ styleOverrides: {
+ ampmSelection: { marginRight: 0 },
+ },
+ },
+ MuiButton: {
+ styleOverrides: {
+ root: ({ theme, ownerState }) => ({
+ ...(ownerState.size === 'medium' && {
+ padding: theme.spacing('6px', '8px'),
+ }),
+ }),
+ },
+ },
+};
+
+export default function MainDemo() {
+ const brandingTheme = useTheme();
+ const isMobile = useMediaQuery(brandingTheme.breakpoints.down('sm'));
+ const isTablet = useMediaQuery(brandingTheme.breakpoints.up('md'));
+ const isDesktop = useMediaQuery(brandingTheme.breakpoints.up('xl'));
+
+ const [showCustomTheme, setShowCustomTheme] = React.useState(false);
+
+ const toggleCustomTheme = () => {
+ setShowCustomTheme((prev) => !prev);
+ };
+
+ const theme = createTheme({ palette: { mode: brandingTheme.palette.mode } });
+ const customTheme = createTheme(brandingTheme, {
+ components,
+ shape: { borderRadius: 8 },
+ typography: { fontFamily: ['"Inter", "sans-serif"'].join(',') },
+ });
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+ {isTablet && (
+
+
+
+
+ )}
+
+
+ {isDesktop && (
+
+
+
+
+ )}
+
+
+
+
+ );
+}
diff --git a/docs/src/modules/components/overview/WorldMapSvg.tsx b/docs/src/modules/components/overview/WorldMapSvg.tsx
new file mode 100644
index 000000000000..9818f694d745
--- /dev/null
+++ b/docs/src/modules/components/overview/WorldMapSvg.tsx
@@ -0,0 +1,123 @@
+import * as React from 'react';
+import { styled, useTheme } from '@mui/material/styles';
+import clsx from 'clsx';
+
+const Continent = styled('g')(({ theme }) => ({
+ cursor: 'pointer',
+ opacity: 0.9,
+ '&:hover ': { opacity: 1 },
+ '&.selected': {
+ fill: theme.palette.primary.main,
+ },
+}));
+
+export type ContinentClickHandler = (event: React.MouseEvent, timezone: string) => void;
+
+type WorldMapSvgProps = {
+ onClickContinent: ContinentClickHandler;
+ selectedTimezone: string | null;
+};
+
+export default function WorldMapSvg({ onClickContinent, selectedTimezone }: WorldMapSvgProps) {
+ const brandingTheme = useTheme();
+
+ const getMapBaseColor = (lightness: number, opacity: number = 1) => {
+ return brandingTheme.palette.mode === 'light'
+ ? `hsla(210,20%,${lightness}%, ${opacity * 100}%)`
+ : `hsla(210,20%,${lightness}%, ${opacity * 100}%)`;
+ };
+
+ const timezones: { [key: string]: string } = {
+ europe: 'Europe/Paris',
+ asia: 'Asia/Hong_kong',
+ southAmerica: 'America/Sao_Paulo',
+ northAmerica: 'America/Chicago',
+ africa: 'Africa/Casablanca',
+ australia: 'Australia/Brisbane',
+ };
+ // TODO: simplify SVG
+ return (
+
+ onClickContinent(e, timezones.northAmerica)}
+ >
+
+
+
+
+
+
+
+
+
+
+ onClickContinent(e, timezones.southAmerica)}
+ >
+
+
+ onClickContinent(e, timezones.europe)}
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+ onClickContinent(e, timezones.asia)}
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ onClickContinent(e, timezones.africa)}
+ >
+
+
+
+ onClickContinent(e, timezones.australia)}
+ >
+
+
+
+
+
+ );
+}
diff --git a/docs/src/modules/components/overview/XLogo.tsx b/docs/src/modules/components/overview/XLogo.tsx
new file mode 100644
index 000000000000..472fb773d5bb
--- /dev/null
+++ b/docs/src/modules/components/overview/XLogo.tsx
@@ -0,0 +1,29 @@
+import * as React from 'react';
+import Typography from '@mui/material/Typography';
+// @ts-ignore
+import IconImage from 'docs/src/components/icon/IconImage';
+
+export default function XLogo() {
+ return (
+ ({
+ color: 'primary.600',
+ display: 'flex',
+ alignItems: 'center',
+ justifyContent: { xs: 'center', md: 'flex-start' },
+ '& > *': { mr: 1 },
+ ...theme.applyDarkStyles({
+ color: 'primary.400',
+ }),
+ }),
+ ]}
+ >
+ MUI X
+
+ );
+}
diff --git a/docs/src/modules/components/overview/mainDemo/Birthday.tsx b/docs/src/modules/components/overview/mainDemo/Birthday.tsx
new file mode 100644
index 000000000000..80d58a8139fe
--- /dev/null
+++ b/docs/src/modules/components/overview/mainDemo/Birthday.tsx
@@ -0,0 +1,34 @@
+import * as React from 'react';
+import dayjs from 'dayjs';
+import Button from '@mui/material/Button';
+import Card from '@mui/material/Card';
+import Stack from '@mui/material/Stack';
+import InputAdornment from '@mui/material/InputAdornment';
+import CakeIcon from '@mui/icons-material/Cake';
+import { DateField } from '@mui/x-date-pickers/DateField';
+
+export default function Birthday() {
+ return (
+
+
+
+
+
+ ),
+ }}
+ />
+
+ Submit
+
+
+
+ );
+}
diff --git a/docs/src/modules/components/overview/mainDemo/Clock.tsx b/docs/src/modules/components/overview/mainDemo/Clock.tsx
new file mode 100644
index 000000000000..2b1b1d5eb80b
--- /dev/null
+++ b/docs/src/modules/components/overview/mainDemo/Clock.tsx
@@ -0,0 +1,52 @@
+import * as React from 'react';
+import dayjs, { Dayjs } from 'dayjs';
+import { styled } from '@mui/material/styles';
+import Card from '@mui/material/Card';
+import { StaticTimePicker } from '@mui/x-date-pickers/StaticTimePicker';
+import {
+ PickersLayoutProps,
+ usePickerLayout,
+ pickersLayoutClasses,
+ PickersLayoutRoot,
+ PickersLayoutContentWrapper,
+} from '@mui/x-date-pickers/PickersLayout';
+import { TimeView } from '@mui/x-date-pickers/models';
+
+const StyledLayout = styled(PickersLayoutRoot)({
+ overflow: 'auto',
+ minWidth: 'fit-content',
+ [`.${pickersLayoutClasses.toolbar}`]: {
+ padding: '4px 16px',
+ },
+ [`.${pickersLayoutClasses.contentWrapper}`]: {
+ '& .MuiTimeClock-root': {
+ width: 'fit-content',
+ },
+ '& .MuiPickersArrowSwitcher-root': {
+ justifyContent: 'space-between',
+ width: '100%',
+ right: 0,
+ top: '2px',
+ },
+ },
+});
+
+function CustomLayout(props: PickersLayoutProps) {
+ const { actionBar, content, toolbar } = usePickerLayout(props);
+ return (
+
+ {toolbar}
+
+ {content}
+ {actionBar}
+
+
+ );
+}
+export default function Clock() {
+ return (
+
+
+
+ );
+}
diff --git a/docs/src/modules/components/overview/mainDemo/DateRangeWithShortcuts.tsx b/docs/src/modules/components/overview/mainDemo/DateRangeWithShortcuts.tsx
new file mode 100644
index 000000000000..a197487ce22d
--- /dev/null
+++ b/docs/src/modules/components/overview/mainDemo/DateRangeWithShortcuts.tsx
@@ -0,0 +1,114 @@
+import * as React from 'react';
+import dayjs, { Dayjs } from 'dayjs';
+import { useTheme } from '@mui/material/styles';
+import useMediaQuery from '@mui/material/useMediaQuery';
+import Card from '@mui/material/Card';
+import { StaticDateRangePicker } from '@mui/x-date-pickers-pro/StaticDateRangePicker';
+import { PickersShortcutsItem } from '@mui/x-date-pickers/PickersShortcuts';
+import {
+ PickersLayoutProps,
+ usePickerLayout,
+ pickersLayoutClasses,
+ PickersLayoutRoot,
+ PickersLayoutContentWrapper,
+} from '@mui/x-date-pickers/PickersLayout';
+import { DateRange } from '@mui/x-date-pickers-pro/models';
+
+const shortcutsItems: PickersShortcutsItem>[] = [
+ {
+ label: 'This Week',
+ getValue: () => {
+ const today = dayjs();
+ return [today.startOf('week'), today.endOf('week')];
+ },
+ },
+ {
+ label: 'Last Week',
+ getValue: () => {
+ const today = dayjs();
+ const prevWeek = today.subtract(7, 'day');
+ return [prevWeek.startOf('week'), prevWeek.endOf('week')];
+ },
+ },
+ {
+ label: 'Last 7 Days',
+ getValue: () => {
+ const today = dayjs();
+ return [today.subtract(7, 'day'), today];
+ },
+ },
+ {
+ label: 'Current Month',
+ getValue: () => {
+ const today = dayjs();
+ return [today.startOf('month'), today.endOf('month')];
+ },
+ },
+ {
+ label: 'Next Month',
+ getValue: () => {
+ const today = dayjs();
+ const startOfNextMonth = today.endOf('month').add(1, 'day');
+ return [startOfNextMonth, startOfNextMonth.endOf('month')];
+ },
+ },
+ { label: 'Reset', getValue: () => [null, null] },
+];
+
+interface CustomLayoutProps extends PickersLayoutProps, Dayjs, 'day'> {
+ isHorizontal?: boolean;
+}
+function CustomLayout(props: CustomLayoutProps) {
+ const { isHorizontal, ...other } = props;
+ const { tabs, content, shortcuts } = usePickerLayout(other);
+
+ return (
+
+ {shortcuts}
+
+ {tabs}
+ {content}
+
+
+ );
+}
+
+export default function DateRangeWithShortcuts() {
+ const theme = useTheme();
+ const showTwoCalendars = useMediaQuery('(min-width:700px)');
+ const lgDown = useMediaQuery(theme.breakpoints.down('lg'));
+ const smUp = useMediaQuery(theme.breakpoints.up('sm'));
+ const xlDown = useMediaQuery(theme.breakpoints.down('xl'));
+ return (
+
+
+
+ );
+}
diff --git a/docs/src/modules/components/overview/mainDemo/DigitalClock.tsx b/docs/src/modules/components/overview/mainDemo/DigitalClock.tsx
new file mode 100644
index 000000000000..a73e74007fca
--- /dev/null
+++ b/docs/src/modules/components/overview/mainDemo/DigitalClock.tsx
@@ -0,0 +1,67 @@
+import * as React from 'react';
+import { Dayjs } from 'dayjs';
+import { styled } from '@mui/material/styles';
+import Card from '@mui/material/Card';
+import Paper from '@mui/material/Paper';
+import Typography from '@mui/material/Typography';
+import { StaticTimePicker } from '@mui/x-date-pickers/StaticTimePicker';
+import {
+ PickersLayoutProps,
+ usePickerLayout,
+ pickersLayoutClasses,
+ PickersLayoutRoot,
+ PickersLayoutContentWrapper,
+} from '@mui/x-date-pickers/PickersLayout';
+import { renderMultiSectionDigitalClockTimeView } from '@mui/x-date-pickers/timeViewRenderers';
+import { TimeView } from '@mui/x-date-pickers/models';
+import { TimePickerViewRenderers } from '@mui/x-date-pickers/TimePicker/shared';
+
+const StyledLayout = styled(PickersLayoutRoot)({
+ overflow: 'auto',
+ [`.${pickersLayoutClasses.contentWrapper}`]: {
+ '& .MuiClock-root': {
+ width: 'fit-content',
+ },
+ },
+});
+
+function CustomLayout(props: PickersLayoutProps) {
+ const { actionBar, content } = usePickerLayout(props);
+ return (
+
+
+ {content}
+ {actionBar}
+
+
+ );
+}
+export default function DigitalClock() {
+ return (
+
+
+ Book now!
+
+ `1px solid ${theme.palette.divider}`,
+ flexWrap: 'wrap',
+ padding: 0,
+ }}
+ >
+
+ }
+ />
+
+
+ );
+}
diff --git a/docs/src/modules/components/overview/mainDemo/FlightPicker.tsx b/docs/src/modules/components/overview/mainDemo/FlightPicker.tsx
new file mode 100644
index 000000000000..d75649a27537
--- /dev/null
+++ b/docs/src/modules/components/overview/mainDemo/FlightPicker.tsx
@@ -0,0 +1,31 @@
+import * as React from 'react';
+import Card from '@mui/material/Card';
+import Typography from '@mui/material/Typography';
+import InputAdornment from '@mui/material/InputAdornment';
+import FlightLandIcon from '@mui/icons-material/FlightLand';
+import FlightTakeoffIcon from '@mui/icons-material/FlightTakeoff';
+import { DateRangePicker } from '@mui/x-date-pickers-pro/DateRangePicker';
+
+export default function FlightPicker() {
+ return (
+
+
+ Book your flight
+
+ ({
+ label: position === 'start' ? 'Outbound' : 'Inbound',
+ InputProps: {
+ startAdornment: (
+
+ {position === 'start' ? : }
+
+ ),
+ },
+ }),
+ }}
+ />
+
+ );
+}
diff --git a/docs/src/modules/components/overview/mainDemo/PickerButton.tsx b/docs/src/modules/components/overview/mainDemo/PickerButton.tsx
new file mode 100644
index 000000000000..0dc82b364e0f
--- /dev/null
+++ b/docs/src/modules/components/overview/mainDemo/PickerButton.tsx
@@ -0,0 +1,71 @@
+import * as React from 'react';
+import dayjs, { Dayjs } from 'dayjs';
+import Button from '@mui/material/Button';
+import Card from '@mui/material/Card';
+import CalendarTodayRoundedIcon from '@mui/icons-material/CalendarTodayRounded';
+import { UseDateFieldProps } from '@mui/x-date-pickers/DateField';
+import { DatePicker } from '@mui/x-date-pickers/DatePicker';
+import {
+ BaseSingleInputFieldProps,
+ DateValidationError,
+ FieldSection,
+} from '@mui/x-date-pickers/models';
+
+interface ButtonFieldProps
+ extends UseDateFieldProps,
+ BaseSingleInputFieldProps {
+ setOpen?: React.Dispatch>;
+}
+
+function ButtonField(props: ButtonFieldProps) {
+ const {
+ setOpen,
+ label,
+ id,
+ disabled,
+ InputProps: { ref } = {},
+ inputProps: { 'aria-label': ariaLabel } = {},
+ } = props;
+
+ return (
+ setOpen?.((prev) => !prev)}
+ startIcon={ }
+ sx={{ minWidth: 'fit-content' }}
+ fullWidth
+ >
+ {label ? `${label}` : 'Pick a date'}
+
+ );
+}
+
+export default function PickerButton() {
+ const [value, setValue] = React.useState(dayjs('2023-04-17'));
+ const [open, setOpen] = React.useState(false);
+
+ return (
+
+ setValue(newValue)}
+ slots={{ field: ButtonField }}
+ slotProps={{
+ field: { setOpen } as any,
+ nextIconButton: { size: 'small' },
+ previousIconButton: { size: 'small' },
+ }}
+ open={open}
+ onClose={() => setOpen(false)}
+ onOpen={() => setOpen(true)}
+ views={['day', 'month', 'year']}
+ />
+
+ );
+}
diff --git a/docs/src/modules/components/overview/mainDemo/ThemeToggleGroup.tsx b/docs/src/modules/components/overview/mainDemo/ThemeToggleGroup.tsx
new file mode 100644
index 000000000000..5483088efd98
--- /dev/null
+++ b/docs/src/modules/components/overview/mainDemo/ThemeToggleGroup.tsx
@@ -0,0 +1,63 @@
+import * as React from 'react';
+import useMediaQuery from '@mui/material/useMediaQuery';
+import { styled, useTheme } from '@mui/material/styles';
+import ToggleButton from '@mui/material/ToggleButton';
+import ToggleButtonGroup, { toggleButtonGroupClasses } from '@mui/material/ToggleButtonGroup';
+import Paper from '@mui/material/Paper';
+import SettingsSuggestIcon from '@mui/icons-material/SettingsSuggest';
+import AutoFixHighIcon from '@mui/icons-material/AutoFixHigh';
+
+const StyledToggleButtonGroup = styled(ToggleButtonGroup)(({ theme }) => ({
+ flexGrow: 1,
+ gap: theme.spacing(1),
+ padding: theme.spacing(0.8),
+ [`& .${toggleButtonGroupClasses.grouped}`]: {
+ border: 0,
+ borderRadius: theme.shape.borderRadius,
+ },
+}));
+
+export type ThemeToggleGroupProps = {
+ showCustomTheme: boolean;
+ toggleCustomTheme: () => void;
+};
+
+export default function ThemeToggleGroup({
+ showCustomTheme,
+ toggleCustomTheme,
+}: ThemeToggleGroupProps) {
+ const theme = useTheme();
+ const isMobile = useMediaQuery(theme.breakpoints.down('sm'));
+
+ return (
+
+ {
+ if (newValue !== null) {
+ toggleCustomTheme();
+ }
+ }}
+ exclusive
+ size="small"
+ >
+
+
+ {isMobile && 'Custom Theme'}
+
+
+
+ {isMobile && 'Default Theme'}
+
+
+
+ );
+}
diff --git a/packages/x-date-pickers/src/PickersTextField/PickersTextField.tsx b/packages/x-date-pickers/src/PickersTextField/PickersTextField.tsx
index 0303989d847c..1ba9e2b3f1d1 100644
--- a/packages/x-date-pickers/src/PickersTextField/PickersTextField.tsx
+++ b/packages/x-date-pickers/src/PickersTextField/PickersTextField.tsx
@@ -139,6 +139,7 @@ const PickersTextField = React.forwardRef(function PickersTextField(
areAllSectionsEmpty={areAllSectionsEmpty}
onClick={onClick}
onKeyDown={onKeyDown}
+ onKeyUp={onKeyUp}
onInput={onInput}
onPaste={onPaste}
endAdornment={endAdornment}