Reach UI (@reach/dialog)

Accessible React modal dialog with built-in focus trapping, scroll locking, and WAI-ARIA compliant markup out of the box.

Library
npm
v0.18.0
5,969stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
52/100Fair
Development Activity0
Maintenance44
Community64
Maturity60
Momentum40

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
63/100Good
Architecture78
Code Quality62
Innovation55
Learning Curve55

@reach/dialog is the modal/dialog primitive from the Reach UI component collection, a set of accessible, unstyled React components built directly against the WAI-ARIA Authoring Practices. It ships a high-level Dialog component alongside lower-level DialogOverlay/DialogContent/DialogInner primitives, so teams can either drop in a fully accessible modal in a few lines or compose their own styled dialog on top of the same accessible foundation.

Internally it delegates focus trapping to react-focus-lock and scroll locking to react-remove-scroll, and manages the accessibility details most hand-rolled modals get wrong: escape-to-dismiss, outside-click dismissal, returning focus to the triggering element on close, and marking background content aria-hidden while the dialog is open. Note that Reach UI’s maintainers have marked the project unmaintained (per the repo README), so it’s best suited for teams who want a stable, already-audited accessible dialog implementation rather than one receiving active feature development.

What You Get

  • The high-level Dialog component plus lower-level DialogOverlay/DialogContent/DialogInner primitives for custom composition
  • Built-in focus lock (via react-focus-lock) and scroll lock (via react-remove-scroll), each with an escape hatch to opt out if needed
  • Automatic aria-hidden management for background content, plus Escape-key and outside-click dismissal wired to an onDismiss callback
  • A companion styles.css file with baseline dialog styling that can be imported as-is or ignored in favor of fully custom CSS

Common Use Cases

  • Accessible confirmation and alert modals
  • Form overlays and multi-step dialogs
  • Design-system foundations for a themed modal component
  • Retrofitting WAI-ARIA compliance onto an existing custom modal

Under The Hood

Architecture The package composes four layered components (DialogWrapperDialogInnerDialogOverlayDialogContent) around a single high-level Dialog export, all defined in packages/dialog/src/reach-dialog.tsx. DialogWrapper renders its children through a Portal (from the sibling @reach/portal package) and provides an isOpen flag via a lightweight context built with @reach/utilscreateContext helper. DialogInner wraps children in react-focus-lock’s FocusLock and react-remove-scroll’s RemoveScroll, composing dismissal handlers (Escape key, outside click) through a shared composeEventHandlers utility. DialogContent applies the actual ARIA attributes (role="dialog", aria-modal). A hand-rolled createAriaHider function walks the direct children of document.body at mount time to mark dialog siblings aria-hidden, restoring original values on cleanup, rather than relying on an external library for that behavior. The package depends on two sibling reach-ui packages (@reach/portal, @reach/polymorphic) and @reach/utils, reflecting the monorepo’s compositional design of small, independently publishable accessible primitives.

Tech Stack Written in TypeScript against a React peer dependency of ^16.8.0 || 17.x (CI exercises React 16/17/18 via aliased package installs), bundled with tsup through a shared @reach-internal/dev config, and tested with Vitest plus vitest-axe for automated accessibility assertions and sinon for fake timers. The monorepo uses pnpm workspaces with Turborepo to orchestrate builds across roughly twenty sibling packages, and Changesets for versioning and publishing. Runtime dependencies are kept minimal and delegated to two focused libraries — react-focus-lock for focus trapping and react-remove-scroll for scroll locking — rather than reimplementing either.

Code Quality The package ships two test files — one exercising interaction behavior (open/close state, focus handling, dismiss callbacks) and one running axe-core accessibility audits via vitest-axe — using @testing-library/react and @testing-library/user-event through a shared internal test-utils wrapper. Source is fully typed TypeScript with exported prop types and a shared Polymorphic.ForwardRefComponent typing pattern used across the monorepo for the as prop. ESLint and Prettier are configured at the monorepo root, and GitHub Actions workflows run tests and releases on push. That said, the project’s own README states Reach UI “is currently not maintained,” and its last release shipped as a prerelease in October 2022 — so while existing practices (types, tests, linting, CI) are solid, the package receives no active maintenance or bug fixes.

API Design The public API is deliberately minimal: a single <Dialog isOpen onDismiss> component covers the large majority of use cases with just two required-in-practice props, while DialogOverlay/DialogContent are exposed separately only for consumers who need custom styling or the polymorphic as prop. This layered “simple thing simple, complex thing possible” API predates and closely parallels patterns later popularized by Radix UI and Headless UI. Nothing here is architecturally novel by current standards — headless, unstyled accessible-primitive libraries are now a well-established category — but @reach/dialog was an early, influential example of the pattern in the React ecosystem.

Used by 10 apps in this directory

JavaScript
90%
Other

CodeSandbox

Code Editors · Developer Tools

13,640

Instantly ready browser-based IDE that runs full npm dependency resolution and transpilation entirely client-side, with no server needed.

View details
69
Repo Health
76
Technical
62
Dependency
Built with
JavaScript90%
Updated 1 weeks ago
JavaScript
90%
Other

CodeSandbox

Code Editors · Developer Tools

13,640

Instantly ready browser-based IDE that runs full npm dependency resolution and transpilation entirely client-side, with no server needed.

View details
69
Repo Health
76
Technical
62
Dependency
Built with
JavaScript90%
Updated 1 weeks ago
JavaScript
90%
Other

CodeSandbox

Code Editors · Developer Tools

13,640

Instantly ready browser-based IDE that runs full npm dependency resolution and transpilation entirely client-side, with no server needed.

View details
69
Repo Health
76
Technical
62
Dependency
Built with
JavaScript90%
Updated 1 weeks ago
JavaScript
90%
Other

CodeSandbox

Code Editors · Developer Tools

13,640

Instantly ready browser-based IDE that runs full npm dependency resolution and transpilation entirely client-side, with no server needed.

View details
69
Repo Health
76
Technical
62
Dependency
Built with
JavaScript90%
Updated 1 weeks ago
JavaScript
90%
Other

CodeSandbox

Code Editors · Developer Tools

13,640

Instantly ready browser-based IDE that runs full npm dependency resolution and transpilation entirely client-side, with no server needed.

View details
69
Repo Health
76
Technical
62
Dependency
Built with
JavaScript90%
Updated 1 weeks ago
JavaScript
90%
Other

CodeSandbox

Code Editors · Developer Tools

13,640

Instantly ready browser-based IDE that runs full npm dependency resolution and transpilation entirely client-side, with no server needed.

View details
69
Repo Health
76
Technical
62
Dependency
Built with
JavaScript90%
Updated 1 weeks ago
TypeScript
50%
ZLIB

Portainer

Devops

38,446

A lightweight, open-source web UI that puts Docker, Kubernetes, and Podman management within reach of any team—no CLI expertise required.

View details
92
Repo Health
79
Technical
65
Dependency
Built with
TypeScript50%
Go38%
Updated 5 days ago
TypeScript
50%
ZLIB

Portainer

Devops

38,446

A lightweight, open-source web UI that puts Docker, Kubernetes, and Podman management within reach of any team—no CLI expertise required.

View details
92
Repo Health
79
Technical
65
Dependency
Built with
TypeScript50%
Go38%
Updated 5 days ago
TypeScript
50%
ZLIB

Portainer

Devops

38,446

A lightweight, open-source web UI that puts Docker, Kubernetes, and Podman management within reach of any team—no CLI expertise required.

View details
92
Repo Health
79
Technical
65
Dependency
Built with
TypeScript50%
Go38%
Updated 5 days ago

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search