Skip to content

@radix-ui/react-dialog: Accessibility error inside shadow dom #3484

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
nayounsang opened this issue Apr 18, 2025 · 2 comments · May be fixed by #3507
Open

@radix-ui/react-dialog: Accessibility error inside shadow dom #3484

nayounsang opened this issue Apr 18, 2025 · 2 comments · May be fixed by #3507

Comments

@nayounsang
Copy link
Contributor

nayounsang commented Apr 18, 2025

Bug report

Current Behavior

  • Even if I write a Title inside Content, the following error occurs
`DialogContent` requires a `DialogTitle` for the component to be accessible for screen reader users.

If you want to hide the `DialogTitle`, you can wrap it with our VisuallyHidden component.

For more information, see 

...
<Dialog.Content>
  <Dialog.Title>Hello World</Dialog.Title>
</Dialog.Content>

Expected behavior

  • If the title exists, an error should not occur

Reproducible example

CodeSandbox Template

import React, { useRef, useState } from "react";
import root from "react-shadow";
import {
  Dialog,
  DialogTrigger,
  DialogContent,
  DialogTitle,
  DialogDescription,
  DialogPortal,
  DialogOverlay,
} from "@radix-ui/react-dialog";
import { VisuallyHidden } from "@radix-ui/react-visually-hidden";

export default function App() {
  const [open, setOpen] = useState(false);
  const [container, setContainer] = useState<HTMLDivElement | null>(null);

  return (
    <Dialog open={open} onOpenChange={setOpen}>
      <DialogTrigger asChild>
        <button>Open Dialog</button>
      </DialogTrigger>

      <root.div>
        <div
          ref={setContainer}
          style={{ position: "relative", zIndex: 9999, inset: 0 }}
        >
          {container && (
            <DialogPortal container={container}>
              <DialogOverlay
                style={{
                  position: "fixed",
                  inset: 0,
                  backgroundColor: "rgba(0,0,0,0.4)",
                }}
              />
              <DialogContent
                style={{
                  background: "white",
                  padding: "2rem",
                  borderRadius: "1rem",
                  position: "fixed",
                  top: "50%",
                  left: "50%",
                  transform: "translate(-50%, -50%)",
                }}
              >
                <DialogTitle>Test Dialog</DialogTitle>
                <DialogDescription>
                  This is a test dialog inside Shadow DOM.
                </DialogDescription>
                <button onClick={() => setOpen(false)}>Close</button>
              </DialogContent>
            </DialogPortal>
          )}
        </div>
      </root.div>
    </Dialog>
  );
}

Suggested solution

We need to figure out how error validation logic works.
See

const TitleWarning: React.FC<TitleWarningProps> = ({ titleId }) => {
  const titleWarningContext = useWarningContext(TITLE_WARNING_NAME);

  const MESSAGE = `\`${titleWarningContext.contentName}\` requires a \`${titleWarningContext.titleName}\` for the component to be accessible for screen reader users.

If you want to hide the \`${titleWarningContext.titleName}\`, you can wrap it with our VisuallyHidden component.

For more information, see https://radix-ui.com/primitives/docs/components/${titleWarningContext.docsSlug}`;

  React.useEffect(() => {
    if (titleId) {
      const hasTitle = document.getElementById(titleId);
      if (!hasTitle) console.error(MESSAGE);
    }
  }, [MESSAGE, titleId]);

  return null;
};

Additional context

useId and VisuallyHidden do not work.
This also applies to description related warnings.

Your environment

Software Name(s) Version
Radix Package(s) "@radix-ui/react-dialog 1.1.6
React n/a 18
Browser chrome 134.0.6998.118
Assistive tech
Node n/a 20
npm/yarn/pnpm yarn 4
Operating System mac 14
@nayounsang
Copy link
Contributor Author

nayounsang commented Apr 18, 2025

  1. If it's a warning as the name suggests(TitleWarning), it should be console.warn.
  2. In shadow dom, document.getElementId doesn't work.

@nayounsang
Copy link
Contributor Author

nayounsang commented Apr 18, 2025

Fixing error validate logic requires the maintainer's opinion(Maybe it's not worth fixing.). However, as the name of TitleWarning suggests, I'm going to try fixing it to console.warn instead of console.error. Is that okay?
In a completely different way, there is also a way to prevent errors by injecting shadow host ref when using shadow DOM. (It might be a bit annoying for developers, though haha)

// for ex..
<DialogContent shadowHost={ref.current}>{children}</DialogContent>

const hasTitle = host ? host.shadowRoot.geElementById() : document.getElementById()

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant