Modal: Expose ariaLabel prop to use with custom header element (#112668)

add optional aria-label for modal when passing custom header element
This commit is contained in:
Ashley Harrison
2025-10-21 16:09:53 +01:00
committed by GitHub
parent 451004d152
commit 59dedb387f
9 changed files with 45 additions and 22 deletions
@@ -2,7 +2,7 @@ import { css } from '@emotion/css';
import { useRef, useEffect } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { Trans } from '@grafana/i18n';
import { t, Trans } from '@grafana/i18n';
import { Button, Icon, Modal, useStyles2 } from '@grafana/ui';
type ConfirmModalProps = {
@@ -33,6 +33,7 @@ export function ConfirmModal({ isOpen, onCancel, onDiscard, onCopy }: ConfirmMod
</span>
</div>
}
ariaLabel={t('grafana-sql.components.confirm-modal.warning', 'Warning')}
onDismiss={onCancel}
isOpen={isOpen}
>
@@ -21,8 +21,6 @@ const meta: Meta = {
controls: {
exclude: ['className', 'contentClassName', 'onDismiss', 'onClickBackdrop'],
},
// TODO fix a11y issue in story and remove this
a11y: { test: 'off' },
},
args: {
body: oneLineTrim(`Id incididunt do pariatur qui labore. Sint culpa irure cillum et ullamco proident. Deserunt ipsum velit dolore est enim proident dolore consectetur. Et cillum tempor pariatur et. Est tempor cillum ad id nulla. Cillum ut proident
@@ -92,7 +90,7 @@ export const WithTabs: StoryFn = (args) => {
);
return (
<div>
<Modal title={modalHeader} isOpen={true}>
<Modal ariaLabel={args.title} title={modalHeader} isOpen={true}>
<TabContent>
{activeTab === tabs[0].value && <div>{args.body}</div>}
{activeTab === tabs[1].value && <div>Second tab content</div>}
@@ -110,7 +108,8 @@ WithTabs.args = {
export const UsingContentClassName: StoryFn = ({ title, body, ...args }) => {
const override = {
modalContent: css({
backgroundColor: 'darkorange',
backgroundColor: 'red',
color: 'black',
}),
};
return (
@@ -15,13 +15,11 @@ import { Stack } from '../Layout/Stack/Stack';
import { ModalHeader } from './ModalHeader';
import { getModalStyles } from './getModalStyles';
export interface Props {
interface BaseProps {
/** @deprecated no longer used */
icon?: IconName;
/** @deprecated no longer used */
iconTooltip?: string;
/** Title for the modal or custom header element */
title: string | JSX.Element;
className?: string;
contentClassName?: string;
closeOnEscape?: boolean;
@@ -35,9 +33,25 @@ export interface Props {
onClickBackdrop?: () => void;
}
interface WithStringTitleProps extends BaseProps {
/** Title for the modal or custom header element */
title: string;
ariaLabel?: never;
}
interface WithCustomTitleProps extends BaseProps {
/** Title for the modal or custom header element */
title: JSX.Element;
/** aria-label for the dialog. only needed when passing a custom title element */
ariaLabel: string;
}
export type Props = WithStringTitleProps | WithCustomTitleProps;
export function Modal(props: PropsWithChildren<Props>) {
const {
title,
ariaLabel,
children,
isOpen = false,
closeOnEscape = true,
@@ -60,7 +74,12 @@ export function Modal(props: PropsWithChildren<Props>) {
);
// Get props for the dialog and its title
const { dialogProps, titleProps } = useDialog({}, ref);
const { dialogProps, titleProps } = useDialog(
{
'aria-label': ariaLabel,
},
ref
);
if (!isOpen) {
return null;