Skip to content

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

Description

@rheisler-deque

The Drawer component renders a plain <div> 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 <div> has role="dialog" when rendered.
  • The Drawer root <div> 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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions