Ariakit

Unstyled, accessible React components implementing WAI-ARIA patterns for building custom design systems.

Library
npm
v0.4.42
8,628 stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum. How we score it →
89 /100 Excellent
Development Activity 100
Maintenance 96
Community 60
Maturity 60
Momentum 40

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation. How we score it →
94 /100 Excellent
Architecture 92
Code Quality 95
Innovation 88
Learning Curve 100

Ariakit is a toolkit of accessible, unstyled React components built on the WAI-ARIA authoring practices, giving teams composable primitives for dialogs, comboboxes, menus, tabs, forms, and other interactive UI patterns without dictating visual design. Each component ships with sensible default behavior — focus management, keyboard navigation, roving tabindex, and ARIA attribute wiring — that developers can override piece by piece through a low-level hooks API.

Under the hood, Ariakit favors composition over configuration: every component exports a store (from @ariakit/react-store) that holds and updates its state, plus a set of sub-components that consume that store via context, so state can be lifted, shared across components, or driven imperatively when needed. The library is maintained as a multi-framework monorepo — the same core architecture also powers a Solid.js port — and is developed with strict TypeScript, extensive unit and real-browser tests, and a public API stable enough to back production design systems.

What You Get

  • A broad set of accessible component families (Dialog, Combobox, Menu, Tab, Form, Toolbar, Select, Popover, Hovercard, and more) covering the majority of interactive UI patterns.
  • A dedicated state layer (@ariakit/react-store) so component state can be read, shared, or driven imperatively outside of React’s render cycle.
  • Zero built-in styles — full control over markup and CSS while Ariakit handles ARIA roles, keyboard interaction, and focus management.
  • TypeScript-first APIs with per-component prop types and JSDoc, enabling editor-driven discovery of every option.
  • A subpath-exports map so consumers can import a single component’s code without pulling in the rest of the toolkit.
  • A living component gallery and examples site (ariakit.com) documenting each primitive with runnable demos.

Common Use Cases

  • Building an in-house design system that needs accessible primitives without adopting a full UI kit’s visual style.
  • Implementing complex interaction patterns (multi-level menus, comboboxes with async options, nested dialogs) without hand-rolling ARIA and focus-trap logic.
  • Migrating off ad-hoc accessibility patches by replacing custom dropdown/dialog/tab code with tested, spec-compliant components.
  • Powering component libraries that need framework parity across React and Solid from a shared architecture.

Under The Hood

Architecture

The library follows a layered, composable-hooks architecture: each interactive pattern implements a store-backed hook composed via a shared createHook/forwardRef utility layer, which itself layers on more primitive hooks (focusable, disclosure-content) from sibling packages, then is re-exported as a plain component from the public package — a thin proxy layer separating the published API surface from the actual implementation. State lives in a dedicated store package built on a framework-agnostic core store, so state can be read or written outside React’s render cycle and shared across nested components; nested-dialog handling (tree walking, outside-interaction marking, focus restoration) is itself split into isolated, composable helper modules rather than embedded in one large component. This layered separation — public API package, implementation package, state package, framework-agnostic utilities — is mirrored again for a parallel Solid.js port, which is strong evidence the abstraction genuinely generalizes across framework boundaries rather than being React-specific.

Tech Stack

TypeScript in strict mode across a pnpm workspace monorepo containing many interdependent packages; each package builds independently via a purpose-built script that emits type declarations separately from bundling. The documentation and example site is an Astro-based app with embedded live examples of the library, and a companion Next.js app supports additional tooling. Linting and formatting run through a modern Rust-based toolchain rather than the traditional ESLint/Prettier combo, with git hooks enforcing checks locally; releases are automated through a changeset-based versioning workflow. Peer dependencies span a wide range of React major versions, signaling deliberate, ongoing compatibility work rather than a pin to a single release line.

Code Quality

An extensive test suite spans unit tests co-located with source (including dedicated tests for the nested-dialog orchestration logic), a custom testing package built on top of standard React testing utilities, and a separate suite of real-browser tests running across multiple browser engines and mobile platforms — a level of testing rigor uncommon even among accessibility-focused UI libraries. Strict typing is enforced project-wide, and CI runs type-checking, linting, visual-regression, and performance-benchmark jobs on every change. Naming is consistent and descriptive throughout, and responsibilities are kept narrow — the nested-dialog handling alone is broken into many small, single-purpose utility files rather than one large component.

API Design The store-per-component pattern gives consumers an escape hatch to read or set state imperatively without prop-drilling, while the common case — wrapping a disclosure and a dialog — requires almost no boilerplate, a rare balance for a library this granular. Sub-components automatically wire their own ARIA attributes by reading shared context, removing a category of manual ARIA bookkeeping most component libraries leave to consumers. Types are hand-authored per component with full documentation comments, so editor autocomplete surfaces prop documentation inline. What distinguishes it from comparable accessible-component libraries is first-class nested-dialog orchestration — tree walking, marking outside elements inert, and per-dialog focus restoration — built directly into the primitive rather than left for consumers to solve themselves.

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