Frameworks
Monochrome includes component wrappers for React and Vue. They generate the correct HTML structure, IDs, and ARIA attributes. All interactivity comes from the core runtime.
Framework wrappers are completely optional. Monochrome works with plain HTML and any backend. The wrappers are a convenience layer for generating the correct semantic markup.
How It Works
The components in monochrome/react and monochrome/vue generate the correct element structure, IDs, and ARIA attributes that Monochrome needs. They contain no state, no effects, no event handlers, and no client-side logic.
All interactivity comes from the Monochrome runtime, a standalone 2.2kB (2219B) script that uses event delegation on the DOM. It works the same whether the HTML was rendered by React, Vue, on the server, or written by hand.
import "monochrome"
import { Accordion } from "monochrome/react"
export function FAQ() {
return (
<Accordion.Root>
<Accordion.Item>
<Accordion.Header>
<Accordion.Trigger>Is React required?</Accordion.Trigger>
</Accordion.Header>
<Accordion.Panel>
No. React is one way to generate the HTML.
</Accordion.Panel>
</Accordion.Item>
</Accordion.Root>
)
}Both produce the same HTML output. The Monochrome runtime handles the rest.
<div id="mcr:accordion:r1" data-mode="single">
<div>
<h3>
<button id="mct:accordion:r1" aria-expanded="false" aria-controls="mcc:accordion:r1">
Is React required?
</button>
</h3>
<div id="mcc:accordion:r1" role="region" aria-labelledby="mct:accordion:r1" aria-hidden="true" hidden="until-found">
No. React is one way to generate the HTML.
</div>
</div>
</div>Compatible Frameworks
The wrappers work with any project that renders HTML. Client-side SPAs, server-rendered apps, static sites.
- Next.js: Server Components, Client Components, and Pages Router
- Remix: Server or client rendering
- Nuxt: SSR mode, client mode, and static generation
- Astro: React or Vue components in
.astrofiles with noclient:directive - Vite or any SPA: Components render in the browser, Monochrome activates immediately
Because the wrappers are pure HTML output, server-rendered setups can ship zero framework JavaScript to the client. The Monochrome runtime is the only script needed in the browser.
Why Use Wrappers?
Writing the HTML by hand works perfectly, but the wrappers save you from managing IDs and ARIA attributes manually:
| Without wrappers | With wrappers |
|---|---|
Write mct:, mcc:, mcr: IDs by hand | IDs generated automatically |
Set aria-expanded, aria-hidden, role, hidden | Attributes set by the component |
Match aria-controls to content IDs | Wired up internally |
| Remember the correct element structure | Enforced by the component tree |
The output is identical. The wrappers are a convenience layer, not a runtime dependency.
Setup
Install Monochrome and import both the runtime and the framework components:
// App entry point or layout
import "monochrome"import { Menu } from "monochrome/react"The runtime import registers event listeners once. The framework imports are used wherever you need components. Both are fully typed with TypeScript definitions included.