diff --git a/src/components/toast/components.test-pw.tsx b/src/components/toast/components.test-pw.tsx index c7bde04585..78cf2b15f6 100644 --- a/src/components/toast/components.test-pw.tsx +++ b/src/components/toast/components.test-pw.tsx @@ -53,6 +53,26 @@ export const ToastWhenOtherModalRenders = ({ ); }; +export const ToastWithConditionalContent = ({ + ...props +}: Partial) => { + const [isOpen1, setIsOpen1] = useState(false); + const [isOpen2, setIsOpen2] = useState(false); + return ( + <> + + + + + {isOpen1 && "Toast 1"} + + + {isOpen2 && "Toast 2"} + + + ); +}; + export const ToastAllAlign = ({ ...props }: Partial) => { return ( <> diff --git a/src/components/toast/toast-test.stories.tsx b/src/components/toast/toast-test.stories.tsx index 482f033993..bb31d29667 100644 --- a/src/components/toast/toast-test.stories.tsx +++ b/src/components/toast/toast-test.stories.tsx @@ -8,7 +8,7 @@ import Dialog from "../dialog"; export default { title: "Toast/Test", - includeStories: ["Default", "Visual", "ToastWhenOtherModalRenders"], + excludeStories: ["TopAndBottom"], parameters: { info: { disable: true }, chromatic: { @@ -368,3 +368,23 @@ export const ToastWhenOtherModalRenders = () => { ); }; + +export const ToastWithConditionalContent = ({ + ...props +}: Partial) => { + const [isOpen1, setIsOpen1] = useState(false); + const [isOpen2, setIsOpen2] = useState(false); + return ( + <> + + + + + {isOpen1 && "Toast 1"} + + + {isOpen2 && "Toast 2"} + + + ); +}; diff --git a/src/components/toast/toast.component.tsx b/src/components/toast/toast.component.tsx index 93dcfa894d..8afe9834e7 100644 --- a/src/components/toast/toast.component.tsx +++ b/src/components/toast/toast.component.tsx @@ -111,6 +111,9 @@ export const Toast = React.forwardRef( const focusedElementBeforeOpening = useRef(null); const [tabIndex, setTabIndex] = useState(0); + const ariaLabelledBy = `${!isNotice && toastIconId.current} ${ + toastContentId.current + }`; let refToPass = toastRef; if (ref && typeof ref === "object" && "current" in ref) { @@ -266,9 +269,8 @@ export const Toast = React.forwardRef( isNotice={isNotice} data-role="toast-wrapper" role="region" - aria-labelledby={`${!isNotice && toastIconId.current} ${ - toastContentId.current - }`} + aria-hidden={!open} + aria-labelledby={open ? ariaLabelledBy : undefined} > {renderToastContent()} diff --git a/src/components/toast/toast.pw.tsx b/src/components/toast/toast.pw.tsx index 1b66e81be2..9c2f75ac5c 100644 --- a/src/components/toast/toast.pw.tsx +++ b/src/components/toast/toast.pw.tsx @@ -5,6 +5,7 @@ import { ToastProps } from "."; import { ToastComponent, ToastWhenOtherModalRenders, + ToastWithConditionalContent, ToastAllAlign, } from "./components.test-pw"; import { @@ -320,4 +321,19 @@ test.describe("Accessibility tests for Toast component", () => { await checkAccessibility(page); }); + + test("passes accessibility checks when multiple Toasts only have content when opened", async ({ + mount, + page, + }) => { + await mount(); + + // check accessibility when both toasts are closed and have undefined content + await checkAccessibility(page); + + await button(page).nth(0).click(); + + // check accessibility when first toast is open and has defined content + await checkAccessibility(page, toastComponent(page)); + }); }); diff --git a/src/components/toast/toast.test.tsx b/src/components/toast/toast.test.tsx index a779dde73e..6c9dfbaffc 100644 --- a/src/components/toast/toast.test.tsx +++ b/src/components/toast/toast.test.tsx @@ -345,6 +345,22 @@ test("should render with provided `data-` attributes", () => { expect(toast).toHaveAttribute("data-element", "toast-element"); }); +test("should render with accessible name when Toast is open", () => { + render(foobar); + + const toast = screen.getByRole("region"); + + expect(toast).toHaveAccessibleName("Success foobar"); +}); + +test("should not render an accessible region when Toast is closed", () => { + render(foobar); + + const toast = screen.queryByRole("region"); + + expect(toast).not.toBeInTheDocument(); +}); + test("should allow custom data props to be passed to close button to be passed via `closeButtonDataProps`", () => { render(