diff --git a/docs/pages/x/api/date-pickers/pickers-calendar-header.json b/docs/pages/x/api/date-pickers/pickers-calendar-header.json
index 94aa338f027f..b2a50f1ad029 100644
--- a/docs/pages/x/api/date-pickers/pickers-calendar-header.json
+++ b/docs/pages/x/api/date-pickers/pickers-calendar-header.json
@@ -5,6 +5,7 @@
"type": { "name": "string" },
"default": "`${adapter.formats.month} ${adapter.formats.year}`"
},
+ "labelId": { "type": { "name": "string" } },
"slotProps": { "type": { "name": "object" }, "default": "{}" },
"slots": {
"type": { "name": "object" },
diff --git a/docs/pages/x/api/date-pickers/pickers-range-calendar-header.json b/docs/pages/x/api/date-pickers/pickers-range-calendar-header.json
index fbf2f5e605c2..d3c101a847ab 100644
--- a/docs/pages/x/api/date-pickers/pickers-range-calendar-header.json
+++ b/docs/pages/x/api/date-pickers/pickers-range-calendar-header.json
@@ -11,6 +11,7 @@
"type": { "name": "string" },
"default": "`${adapter.formats.month} ${adapter.formats.year}`"
},
+ "labelId": { "type": { "name": "string" } },
"slotProps": { "type": { "name": "object" }, "default": "{}" },
"slots": {
"type": { "name": "object" },
diff --git a/docs/translations/api-docs/date-pickers/pickers-calendar-header/pickers-calendar-header.json b/docs/translations/api-docs/date-pickers/pickers-calendar-header/pickers-calendar-header.json
index 6095d04c8b30..14b1549d337d 100644
--- a/docs/translations/api-docs/date-pickers/pickers-calendar-header/pickers-calendar-header.json
+++ b/docs/translations/api-docs/date-pickers/pickers-calendar-header/pickers-calendar-header.json
@@ -3,6 +3,9 @@
"propDescriptions": {
"classes": { "description": "Override or extend the styles applied to the component." },
"format": { "description": "Format used to display the date." },
+ "labelId": {
+ "description": "Id of the calendar text element. It is used to establish an aria-labelledby
relationship with the calendar grid
element."
+ },
"slotProps": { "description": "The props used for each component slot." },
"slots": { "description": "Overridable component slots." },
"sx": {
diff --git a/docs/translations/api-docs/date-pickers/pickers-range-calendar-header/pickers-range-calendar-header.json b/docs/translations/api-docs/date-pickers/pickers-range-calendar-header/pickers-range-calendar-header.json
index a152174c7d95..9affb9834e6d 100644
--- a/docs/translations/api-docs/date-pickers/pickers-range-calendar-header/pickers-range-calendar-header.json
+++ b/docs/translations/api-docs/date-pickers/pickers-range-calendar-header/pickers-range-calendar-header.json
@@ -4,6 +4,9 @@
"calendars": { "description": "The number of calendars rendered." },
"classes": { "description": "Override or extend the styles applied to the component." },
"format": { "description": "Format used to display the date." },
+ "labelId": {
+ "description": "Id of the calendar text element. It is used to establish an aria-labelledby
relationship with the calendar grid
element."
+ },
"month": { "description": "Month used for this header." },
"monthIndex": { "description": "Index of the month used for this header." },
"slotProps": { "description": "The props used for each component slot." },
diff --git a/packages/x-date-pickers-pro/src/DateRangeCalendar/DateRangeCalendar.test.tsx b/packages/x-date-pickers-pro/src/DateRangeCalendar/DateRangeCalendar.test.tsx
index 1947567216c9..ffa81a05f51b 100644
--- a/packages/x-date-pickers-pro/src/DateRangeCalendar/DateRangeCalendar.test.tsx
+++ b/packages/x-date-pickers-pro/src/DateRangeCalendar/DateRangeCalendar.test.tsx
@@ -25,7 +25,7 @@ import { describeConformance } from 'test/utils/describeConformance';
import { RangePosition } from '../models';
const getPickerDay = (name: string, picker = 'January 2018') =>
- getByRole(screen.getByText(picker)?.parentElement?.parentElement!, 'gridcell', { name });
+ getByRole(screen.getByRole('grid', { name: picker }), 'gridcell', { name });
const dynamicShouldDisableDate = (date, position: RangePosition) => {
if (position === 'end') {
diff --git a/packages/x-date-pickers-pro/src/DateRangeCalendar/DateRangeCalendar.tsx b/packages/x-date-pickers-pro/src/DateRangeCalendar/DateRangeCalendar.tsx
index 1d8bbc4daa79..4d4e418bea87 100644
--- a/packages/x-date-pickers-pro/src/DateRangeCalendar/DateRangeCalendar.tsx
+++ b/packages/x-date-pickers-pro/src/DateRangeCalendar/DateRangeCalendar.tsx
@@ -5,7 +5,8 @@ import useEventCallback from '@mui/utils/useEventCallback';
import useMediaQuery from '@mui/material/useMediaQuery';
import { resolveComponentProps, useSlotProps } from '@mui/base/utils';
import { styled, useThemeProps } from '@mui/material/styles';
-import { unstable_composeClasses as composeClasses } from '@mui/utils';
+import composeClasses from '@mui/utils/composeClasses';
+import useId from '@mui/utils/useId';
import { Watermark } from '@mui/x-license';
import {
applyDefaultDate,
@@ -231,6 +232,7 @@ const DateRangeCalendar = React.forwardRef(function DateRangeCalendar<
const utils = useUtils();
const now = useNow(timezone);
+ const id = useId();
const { rangePosition, onRangePositionChange } = useRangePosition({
rangePosition: rangePositionProp,
@@ -548,10 +550,16 @@ const DateRangeCalendar = React.forwardRef(function DateRangeCalendar<
{calendarMonths.map((monthIndex) => {
const month = visibleMonths[monthIndex];
+ const labelId = `${id}-grid-${monthIndex}-label`;
return (
- {...calendarHeaderProps} month={month} monthIndex={monthIndex} />
+
+ {...calendarHeaderProps}
+ month={month}
+ monthIndex={monthIndex}
+ labelId={labelId}
+ />
className={classes.dayCalendar}
{...calendarState}
@@ -575,6 +583,7 @@ const DateRangeCalendar = React.forwardRef(function DateRangeCalendar<
fixedWeekNumber={fixedWeekNumber}
displayWeekNumber={displayWeekNumber}
timezone={timezone}
+ gridLabelId={labelId}
/>
);
diff --git a/packages/x-date-pickers-pro/src/DesktopDateRangePicker/tests/DesktopDateRangePicker.test.tsx b/packages/x-date-pickers-pro/src/DesktopDateRangePicker/tests/DesktopDateRangePicker.test.tsx
index 98032d863607..4c4476eda2eb 100644
--- a/packages/x-date-pickers-pro/src/DesktopDateRangePicker/tests/DesktopDateRangePicker.test.tsx
+++ b/packages/x-date-pickers-pro/src/DesktopDateRangePicker/tests/DesktopDateRangePicker.test.tsx
@@ -18,8 +18,8 @@ import {
const isJSDOM = /jsdom/.test(window.navigator.userAgent);
-const getPickerDay = (name: string, picker = 'January 2018'): HTMLButtonElement =>
- getByRole(screen.getByText(picker)?.parentElement?.parentElement!, 'gridcell', { name });
+const getPickerDay = (name: string, picker = 'January 2018') =>
+ getByRole(screen.getByRole('grid', { name: picker }), 'gridcell', { name });
describe('', () => {
const { render, clock } = createPickerRenderer({
diff --git a/packages/x-date-pickers-pro/src/PickersRangeCalendarHeader/PickersRangeCalendarHeader.tsx b/packages/x-date-pickers-pro/src/PickersRangeCalendarHeader/PickersRangeCalendarHeader.tsx
index faf5ab4b228a..6657941e84d6 100644
--- a/packages/x-date-pickers-pro/src/PickersRangeCalendarHeader/PickersRangeCalendarHeader.tsx
+++ b/packages/x-date-pickers-pro/src/PickersRangeCalendarHeader/PickersRangeCalendarHeader.tsx
@@ -29,7 +29,7 @@ const PickersRangeCalendarHeader = React.forwardRef(function PickersRangeCalenda
const utils = useUtils();
const localeText = useLocaleText();
- const { calendars, month, monthIndex, ...other } = props;
+ const { calendars, month, monthIndex, labelId, ...other } = props;
const {
format,
slots,
@@ -56,7 +56,7 @@ const PickersRangeCalendarHeader = React.forwardRef(function PickersRangeCalenda
});
if (calendars === 1) {
- return ;
+ return ;
}
const selectNextMonth = () => onMonthChange(utils.addMonths(currentMonth, 1), 'left');
@@ -76,6 +76,7 @@ const PickersRangeCalendarHeader = React.forwardRef(function PickersRangeCalenda
nextLabel={localeText.nextMonth}
slots={slots}
slotProps={slotProps}
+ labelId={labelId}
>
{utils.formatByString(month, format ?? `${utils.formats.month} ${utils.formats.year}`)}
@@ -105,6 +106,10 @@ PickersRangeCalendarHeader.propTypes = {
* @default `${adapter.formats.month} ${adapter.formats.year}`
*/
format: PropTypes.string,
+ /**
+ * Id of the calendar text element.
+ * It is used to establish an `aria-labelledby` relationship with the calendar `grid` element.
+ */
labelId: PropTypes.string,
maxDate: PropTypes.object.isRequired,
minDate: PropTypes.object.isRequired,
diff --git a/packages/x-date-pickers/src/PickersCalendarHeader/PickersCalendarHeader.tsx b/packages/x-date-pickers/src/PickersCalendarHeader/PickersCalendarHeader.tsx
index a172fa35fee2..d49252d9c441 100644
--- a/packages/x-date-pickers/src/PickersCalendarHeader/PickersCalendarHeader.tsx
+++ b/packages/x-date-pickers/src/PickersCalendarHeader/PickersCalendarHeader.tsx
@@ -281,6 +281,10 @@ PickersCalendarHeader.propTypes = {
* @default `${adapter.formats.month} ${adapter.formats.year}`
*/
format: PropTypes.string,
+ /**
+ * Id of the calendar text element.
+ * It is used to establish an `aria-labelledby` relationship with the calendar `grid` element.
+ */
labelId: PropTypes.string,
maxDate: PropTypes.object.isRequired,
minDate: PropTypes.object.isRequired,
diff --git a/packages/x-date-pickers/src/PickersCalendarHeader/PickersCalendarHeader.types.ts b/packages/x-date-pickers/src/PickersCalendarHeader/PickersCalendarHeader.types.ts
index 06cbb152849a..a679a4fe9b6f 100644
--- a/packages/x-date-pickers/src/PickersCalendarHeader/PickersCalendarHeader.types.ts
+++ b/packages/x-date-pickers/src/PickersCalendarHeader/PickersCalendarHeader.types.ts
@@ -67,6 +67,10 @@ export interface PickersCalendarHeaderProps
view: DateView;
reduceAnimations: boolean;
onViewChange?: (view: DateView) => void;
+ /**
+ * Id of the calendar text element.
+ * It is used to establish an `aria-labelledby` relationship with the calendar `grid` element.
+ */
labelId?: string;
/**
* Override or extend the styles applied to the component.
diff --git a/packages/x-date-pickers/src/internals/components/PickersArrowSwitcher/PickersArrowSwitcher.tsx b/packages/x-date-pickers/src/internals/components/PickersArrowSwitcher/PickersArrowSwitcher.tsx
index 617a71eea6fd..2ecae8493f14 100644
--- a/packages/x-date-pickers/src/internals/components/PickersArrowSwitcher/PickersArrowSwitcher.tsx
+++ b/packages/x-date-pickers/src/internals/components/PickersArrowSwitcher/PickersArrowSwitcher.tsx
@@ -79,6 +79,7 @@ export const PickersArrowSwitcher = React.forwardRef(function PickersArrowSwitch
isPreviousHidden,
onGoToPrevious,
previousLabel,
+ labelId,
...other
} = props;
@@ -169,7 +170,7 @@ export const PickersArrowSwitcher = React.forwardRef(function PickersArrowSwitch
)}
{children ? (
-
+
{children}
) : (
diff --git a/packages/x-date-pickers/src/internals/components/PickersArrowSwitcher/PickersArrowSwitcher.types.tsx b/packages/x-date-pickers/src/internals/components/PickersArrowSwitcher/PickersArrowSwitcher.types.tsx
index aaa5552a8c65..0998b6ded18b 100644
--- a/packages/x-date-pickers/src/internals/components/PickersArrowSwitcher/PickersArrowSwitcher.types.tsx
+++ b/packages/x-date-pickers/src/internals/components/PickersArrowSwitcher/PickersArrowSwitcher.types.tsx
@@ -38,6 +38,7 @@ export interface PickersArrowSwitcherProps
isNextHidden?: boolean;
onGoToNext: () => void;
nextLabel: string;
+ labelId?: string;
}
export type PickersArrowSwitcherOwnerState = PickersArrowSwitcherProps;