Skip to content

Commit 3b4f1ca

Browse files
authored
[Dialogs] Fix missing ids on Title and Description (mui#1326)
1 parent 1147c18 commit 3b4f1ca

File tree

6 files changed

+92
-0
lines changed

6 files changed

+92
-0
lines changed

packages/react/src/alert-dialog/description/AlertDialogDescription.tsx

+10
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import * as React from 'react';
33
import PropTypes from 'prop-types';
44
import { useAlertDialogRootContext } from '../root/AlertDialogRootContext';
5+
import { mergeReactProps } from '../../utils/mergeReactProps';
56
import { useComponentRenderer } from '../../utils/useComponentRenderer';
67
import { useEnhancedEffect } from '../../utils/useEnhancedEffect';
78
import { useBaseUiId } from '../../utils/useBaseUiId';
@@ -31,7 +32,16 @@ const AlertDialogDescription = React.forwardRef(function AlertDialogDescription(
3132
};
3233
}, [id, setDescriptionElementId]);
3334

35+
const getProps = React.useCallback(
36+
(externalProps = {}) =>
37+
mergeReactProps(externalProps, {
38+
id,
39+
}),
40+
[id],
41+
);
42+
3443
const { renderElement } = useComponentRenderer({
44+
propGetter: getProps,
3545
render: render ?? 'p',
3646
className,
3747
state,

packages/react/src/alert-dialog/root/AlertDialogRoot.test.tsx

+26
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,32 @@ import { spy } from 'sinon';
88
describe('<AlertDialog.Root />', () => {
99
const { render } = createRenderer();
1010

11+
it('ARIA attributes', async () => {
12+
const { queryByRole, getByText } = await render(
13+
<AlertDialog.Root open>
14+
<AlertDialog.Trigger />
15+
<AlertDialog.Portal>
16+
<AlertDialog.Backdrop />
17+
<AlertDialog.Popup>
18+
<AlertDialog.Title>title text</AlertDialog.Title>
19+
<AlertDialog.Description>description text</AlertDialog.Description>
20+
</AlertDialog.Popup>
21+
</AlertDialog.Portal>
22+
</AlertDialog.Root>,
23+
);
24+
25+
const popup = queryByRole('alertdialog');
26+
expect(popup).not.to.equal(null);
27+
expect(popup).to.have.attribute('aria-modal', 'true');
28+
29+
expect(getByText('title text').getAttribute('id')).to.equal(
30+
popup?.getAttribute('aria-labelledby'),
31+
);
32+
expect(getByText('description text').getAttribute('id')).to.equal(
33+
popup?.getAttribute('aria-describedby'),
34+
);
35+
});
36+
1137
describe('prop: onOpenChange', () => {
1238
it('calls onOpenChange with the new open state', async () => {
1339
const handleOpenChange = spy();

packages/react/src/alert-dialog/title/AlertDialogTitle.tsx

+10
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import * as React from 'react';
33
import PropTypes from 'prop-types';
44
import { useAlertDialogRootContext } from '../root/AlertDialogRootContext';
5+
import { mergeReactProps } from '../../utils/mergeReactProps';
56
import { useComponentRenderer } from '../../utils/useComponentRenderer';
67
import { useEnhancedEffect } from '../../utils/useEnhancedEffect';
78
import { useBaseUiId } from '../../utils/useBaseUiId';
@@ -31,7 +32,16 @@ const AlertDialogTitle = React.forwardRef(function AlertDialogTitle(
3132
};
3233
}, [id, setTitleElementId]);
3334

35+
const getProps = React.useCallback(
36+
(externalProps = {}) =>
37+
mergeReactProps(externalProps, {
38+
id,
39+
}),
40+
[id],
41+
);
42+
3443
const { renderElement } = useComponentRenderer({
44+
propGetter: getProps,
3545
render: render ?? 'h2',
3646
className,
3747
state,

packages/react/src/dialog/description/DialogDescription.tsx

+10
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import * as React from 'react';
33
import PropTypes from 'prop-types';
44
import { useDialogRootContext } from '../root/DialogRootContext';
5+
import { mergeReactProps } from '../../utils/mergeReactProps';
56
import { useComponentRenderer } from '../../utils/useComponentRenderer';
67
import { useEnhancedEffect } from '../../utils/useEnhancedEffect';
78
import { useBaseUiId } from '../../utils/useBaseUiId';
@@ -31,7 +32,16 @@ const DialogDescription = React.forwardRef(function DialogDescription(
3132
};
3233
}, [id, setDescriptionElementId]);
3334

35+
const getProps = React.useCallback(
36+
(externalProps = {}) =>
37+
mergeReactProps(externalProps, {
38+
id,
39+
}),
40+
[id],
41+
);
42+
3443
const { renderElement } = useComponentRenderer({
44+
propGetter: getProps,
3545
render: render ?? 'p',
3646
className,
3747
state,

packages/react/src/dialog/root/DialogRoot.test.tsx

+26
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,32 @@ describe('<Dialog.Root />', () => {
1414

1515
const { render } = createRenderer();
1616

17+
it('ARIA attributes', async () => {
18+
const { queryByRole, getByText } = await render(
19+
<Dialog.Root modal={false} open>
20+
<Dialog.Trigger />
21+
<Dialog.Portal>
22+
<Dialog.Backdrop />
23+
<Dialog.Popup>
24+
<Dialog.Title>title text</Dialog.Title>
25+
<Dialog.Description>description text</Dialog.Description>
26+
</Dialog.Popup>
27+
</Dialog.Portal>
28+
</Dialog.Root>,
29+
);
30+
31+
const popup = queryByRole('dialog');
32+
expect(popup).not.to.equal(null);
33+
expect(popup).to.not.have.attribute('aria-modal');
34+
35+
expect(getByText('title text').getAttribute('id')).to.equal(
36+
popup?.getAttribute('aria-labelledby'),
37+
);
38+
expect(getByText('description text').getAttribute('id')).to.equal(
39+
popup?.getAttribute('aria-describedby'),
40+
);
41+
});
42+
1743
describe('uncontrolled mode', () => {
1844
it('should open the dialog with the trigger', async () => {
1945
const { queryByRole, getByRole } = await render(

packages/react/src/dialog/title/DialogTitle.tsx

+10
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import * as React from 'react';
33
import PropTypes from 'prop-types';
44
import { useDialogRootContext } from '../root/DialogRootContext';
5+
import { mergeReactProps } from '../../utils/mergeReactProps';
56
import { useComponentRenderer } from '../../utils/useComponentRenderer';
67
import { useEnhancedEffect } from '../../utils/useEnhancedEffect';
78
import { useBaseUiId } from '../../utils/useBaseUiId';
@@ -31,7 +32,16 @@ const DialogTitle = React.forwardRef(function DialogTitle(
3132
};
3233
}, [id, setTitleElementId]);
3334

35+
const getProps = React.useCallback(
36+
(externalProps = {}) =>
37+
mergeReactProps(externalProps, {
38+
id,
39+
}),
40+
[id],
41+
);
42+
3443
const { renderElement } = useComponentRenderer({
44+
propGetter: getProps,
3545
render: render ?? 'h2',
3646
className,
3747
state,

0 commit comments

Comments
 (0)