Get Started

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 .astro files with no client: 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 wrappersWith wrappers
Write mct:, mcc:, mcr: IDs by handIDs generated automatically
Set aria-expanded, aria-hidden, role, hiddenAttributes set by the component
Match aria-controls to content IDsWired up internally
Remember the correct element structureEnforced 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.

Next Steps