Accessible UI component library. Best-in-class performance. HTML-first, React and Vue supported.
If you write accessible HTML, monochrome makes it interactive. The DOM is the state; ARIA attributes (aria-expanded, aria-selected, aria-checked) drive every component. No initialization, no mount hooks.
Accordion · Collapsible · Dialog · Menu · Menubar · Popover · Tabs · Tooltip.
Plus an optional client-side router and thin React and Vue wrappers.
npm install monochrome// every component, one flat file. For pages that ship no other
// monochrome import; don't combine with the granular imports below
import "monochrome"
// one component (shared helpers dedupe across entries)
import "monochrome/menu"
// optional router
import "monochrome/router"
// React wrappers: each auto-imports its own core, so one import
// wires markup and behavior, tree-shaken to the components you use
import { Accordion, Menu } from "monochrome/react"
// Vue wrappers, same shape
import { Accordion, Menu } from "monochrome/vue"<script type="module" src="https://unpkg.com/monochrome"></script>
<button id="mct:collapsible:1" aria-expanded="false" aria-controls="mcc:collapsible:1">
Show details
</button>
<div id="mcc:collapsible:1" aria-labelledby="mct:collapsible:1" hidden>
Hidden by default, revealed on click.
</div>The React and Vue wrappers generate the same HTML and ARIA; all interactivity comes from the core.
Core: Baseline 2024. Chrome 114 (2023-05-30), Safari 17
(2023-09-18), and Firefox 125 (2024-04-16). Uses the Popover
API and the native <dialog> element. No polyfills shipped.
Router: Navigation API (Baseline 2026). Chrome 135
(2025-04-01), Safari 26.2 (2025-12-12), and Firefox 147
(2026-01-13). Links are prefetched on hover, focus, and
press, and, from the reader's first interaction, as they
enter the viewport; see docs/router.md.
Older browsers keep full page loads; import "monochrome/router" is a no-op there.
Library development uses Bun 1.4.2. Open a pull request
against main; do not push to it.
bun installThat installs dependencies and points Git at the repo hooks. A commit runs lint, build, and typecheck. No browsers.
To run tests locally:
bun run test:install
bun run testLinux may need
bunx playwright install --with-deps chromium (sudo)
if Chromium will not launch. The full matrix is
bun run test:install:all then bun run test:all.
CI runs that matrix on the pull request.
PRINCIPLES.md holds the
non-negotiables, AGENTS.md how to work in the
repo, and docs/ how each mechanism works. Router notes
live in docs/router.md.
MIT © Colin van Eenige