The hand-rolled modals share the same accessibility gaps:
- no
role="dialog" and no aria-modal="true", so screen readers do not announce them as dialogs
- no focus trap, so Tab walks straight out of the modal into the page behind it while the backdrop still blocks the mouse
- focus is never returned to the trigger on close, so keyboard users land back at the top of the document
- the preview modal never moves focus into itself at all
- the create-folder dialog puts its Escape handler on an inner div, so Escape only works while focus happens to be inside it
- the preview modal backdrop is a clickable
<div> with no keyboard equivalent
@radix-ui/react-dialog is already a dependency and shared/components/ui/dialog.tsx wraps it, so most of this is solved by using what we have.
Where:
frontend/src/components/file-preview/file-preview-modal.tsx
frontend/src/features/dashboard/components/ui/dialogs/create-folder-dialog.tsx
frontend/src/features/dashboard/components/views/search/advance-search-sheet/advanced-search-sheet.tsx
frontend/src/features/upload/components/duplicate-dialog.tsx
frontend/src/shared/components/ui/dialog.tsx
What to do:
- Port these onto the Radix dialog primitive, which gives focus trap, focus restore, Escape, and the ARIA wiring
- Where a custom modal has to stay, add
role="dialog", aria-modal, aria-labelledby, focus-on-open, and focus-restore-on-close
- Move Escape handling to a document listener rather than a element-scoped one
The hand-rolled modals share the same accessibility gaps:
role="dialog"and noaria-modal="true", so screen readers do not announce them as dialogs<div>with no keyboard equivalent@radix-ui/react-dialogis already a dependency andshared/components/ui/dialog.tsxwraps it, so most of this is solved by using what we have.Where:
frontend/src/components/file-preview/file-preview-modal.tsxfrontend/src/features/dashboard/components/ui/dialogs/create-folder-dialog.tsxfrontend/src/features/dashboard/components/views/search/advance-search-sheet/advanced-search-sheet.tsxfrontend/src/features/upload/components/duplicate-dialog.tsxfrontend/src/shared/components/ui/dialog.tsxWhat to do:
role="dialog",aria-modal,aria-labelledby, focus-on-open, and focus-restore-on-close