fix: give every dialog an accessible name and description - #981
Merged
Merged
Conversation
The image, frontmatter and shared toolbar dialogs each rendered a Radix DialogContent without a DialogDescription, so Radix emitted an accessibility warning and screen readers got no description for the dialog. The shared DialogButton primitive was missing DialogTitle as well, which left those dialogs without an accessible name entirely. Each dialog now carries a visually hidden description, the shared primitive carries a title, and a regression test asserts the name/description wiring on all three dialogs. No public API change.
2 tasks done
Contributor
Author
|
Heads-up: the workflows for this PR have not started. As a first-time contribution from a fork they sit behind maintainer approval ("Approve and run all workflows"), so there is currently no CI signal on the PR either way. Verified locally in the meantime:
|
|
🎉 This PR is included in version 4.3.0 🎉 The release is available on: Your semantic-release bot 📦🚀 |
pull Bot
pushed a commit
to LeeeeeeM/editor
that referenced
this pull request
Sep 26, 2026
The English locale is the reference translators copy from, but it was missing keys the UI already uses (strikethrough, sub/superscript, the inline code block language, the dialog close button, the URL-only image instructions) and the dialog descriptions added in mdx-editor#981. Translations could not cover strings they never saw.
pull Bot
pushed a commit
to LeeeeeeM/editor
that referenced
this pull request
Sep 26, 2026
…is set The dialog description added in mdx-editor#981 always mentioned uploading from the device, but without an imageUploadHandler the dialog only accepts a URL. Screen reader users were told about an option that is not there.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Three dialogs render a Radix
Dialog.Contentwithout aDialog.Description, so Radix logsand screen reader users get no description for the dialog. The shared
DialogButtonprimitive was missingDialog.Titleas well, so the dialogs built on it had no accessible name at all.This was reported in #792 for the image dialog. Reading the source showed the same defect in the frontmatter dialog and in the shared toolbar dialog primitive, so the fix covers the defect class rather than the single reported dialog.
Root cause
@radix-ui/react-dialogrequires an accessible name and description onDialogContent, and warns at runtime when either is missing. Verified in the current tree:src/plugins/image/ImageDialog.tsxsrc/plugins/frontmatter/FrontmatterEditor.tsxsrc/plugins/toolbar/primitives/DialogButton.tsxThe one-line way to silence the warning is
aria-describedby={undefined}, but that only mutes the console message — the dialogs remain undescribed for assistive technology, andDialogButtonstill has no accessible name. This PR closes the accessibility gap itself.Changes
src/styles/ui.module.css— add a.visuallyHiddenutility class (standard clip-based visually-hidden pattern) so a description can be rendered for assistive technology without altering the visual design.src/plugins/image/ImageDialog.tsx— addDialog.Descriptionusing a new translatable keyuploadImage.dialogDescription.src/plugins/frontmatter/FrontmatterEditor.tsx— addDialog.Descriptionusing a new translatable keyfrontmatterEditor.dialogDescription.src/plugins/toolbar/primitives/DialogButton.tsx— add a visually hiddenDialog.Title(from the existingtooltipTitleprop) andDialog.Description(from the existingdialogInputPlaceholderprop), so the primitive names and describes itself from props it already receives.src/test/dialog-a11y.test.tsx— regression test that opens all three dialogs, resolves each byrole="dialog"and accessible name, and assertsaria-describedbypoints at an element carrying the expected description.No public API change: the
DialogButtonprop contract is untouched, and the two new translation keys fall back to their English defaults when a consumer provides no translation.Verification
Red/green on the new test, run with
npx vitest --run src/test/dialog-a11y.test.tsx:Tests 3 failed (3). The shared-primitive case failed withUnable to find an accessible element with the role "dialog" and name "Insert YouTube video", independently confirming the missing accessible name.Tests 3 passed (3).Full local gate on the branch:
npm run lint— cleannpm run typecheck— cleannpm run test:once— full suite green (100 passed | 1 skipped), no regressionsRegression risk
Low, and confined to dialog semantics. The descriptions are visually hidden and reuse existing props or default strings, so no rendering or layout changes are expected. The added test guards the wiring against future refactors.
Closes #792