diff --git a/packages/luthor/src/core/toolbar.custom-items.test.tsx b/packages/luthor/src/core/toolbar.custom-items.test.tsx index 369b092..f860d96 100644 --- a/packages/luthor/src/core/toolbar.custom-items.test.tsx +++ b/packages/luthor/src/core/toolbar.custom-items.test.tsx @@ -85,7 +85,10 @@ describe("toolbar custom items", () => { fireEvent.click(screen.getByRole("button", { name: "Web page" })); expect(onSelect).not.toHaveBeenCalled(); - expect(screen.getByText("Embed a web page")).toBeInTheDocument(); + // A labelled modal dialog with a named close button. + const dialog = screen.getByRole("dialog", { name: "Embed a web page" }); + expect(dialog.getAttribute("aria-modal")).toBe("true"); + expect(screen.getByRole("button", { name: "Close" })).toBeInTheDocument(); const submit = screen.getByRole("button", { name: "Embed" }) as HTMLButtonElement; expect(submit.disabled).toBe(true); diff --git a/packages/luthor/src/core/ui.tsx b/packages/luthor/src/core/ui.tsx index 92bafe5..9b88f61 100644 --- a/packages/luthor/src/core/ui.tsx +++ b/packages/luthor/src/core/ui.tsx @@ -5,7 +5,7 @@ * Build freely. Credit kindly. */ -import { useEffect, useLayoutEffect, useRef, useState, type CSSProperties, type ReactNode } from "react"; +import { useEffect, useId, useLayoutEffect, useRef, useState, type CSSProperties, type ReactNode } from "react"; import { createPortal } from "react-dom"; import { ChevronDownIcon, CloseIcon } from "./icons"; import { getOverlayThemeStyleFromElement } from "./overlay-theme"; @@ -353,6 +353,7 @@ export function Dialog({ children: ReactNode; }) { const dialogRef = useRef(null); + const titleId = useId(); useEffect(() => { function handleClickOutside(event: MouseEvent) { @@ -382,10 +383,10 @@ export function Dialog({ return (
-
+
-

{title}

-