dequelabs / dequelabs/cauldron

Drawer: missing role="dialog" and automatic accessible name

Open
#2,428 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
TypeScript
Stars
127
Forks
31
Avg merge
2d 12h
Merged PRs (30d)
8

Description

The `Drawer` component renders a plain `

` with no `role` attribute and no automatic accessible name. Callers who pass `aria-label` or `aria-labelledby` via props are labeling an anonymous div — screen readers ignore that label because there is no role to attach it to. Screen readers do not announce entry into a dialog region when the drawer opens, and virtual-cursor users have no landmark or structural cue that they are in a bounded modal area.

The component already does the right things for containment: `AriaIsolate` hides the rest of the page from AT while open, and `useFocusTrap` constrains keyboard focus. The gap is role announcement and accessible naming.

## Acceptance criteria

- The `Drawer` root `

` has `role="dialog"` when rendered.
- The `Drawer` root `
` has `aria-modal="true"` when `behavior === 'modal'` (the default).
- The `Drawer` automatically receives an accessible name via `aria-labelledby`, following the same pattern used by `Dialog`:
- An auto-generated heading ID (via `useId`) is created by `Drawer` and passed through a `DrawerContext`.
- A `DrawerHeading` sub-component reads the ID from context and applies it as its own `id`, so `aria-labelledby` on the root element always references the visible heading text.
- A dev-mode warning is raised (matching the existing `Dialog` pattern) if the drawer is open but no `DrawerHeading` is present inside it.
- When the `Drawer` opens, focus moves to the heading rather than the drawer container, matching `Dialog`. Focusing the container draws a focus ring around the entire drawer (which looks bad) and is a weaker announcement; focusing the heading fixes both. The `DrawerHeading` takes `tabIndex={-1}` and a ref carried through `DrawerContext` (like `DialogContext.headingRef`), which `Drawer` passes to `useFocusTrap` as its `initialFocusElement`.

## References

- WAI-ARIA Authoring Practices — [Dialog (Modal) Pattern](https://www.w3.org/WAI/ARIA/apg/patterns/dialog-modal/)
- `Dialog` component implementation of the same pattern: `packages/react/src/components/Dialog/index.tsx`
- Resolved for `Dialog` in #1259

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.