
It currently includes 4 prebuilt UI components (accordion, collapsible, menu, and tabs) and works with any server-rendered stack, static site generator, or React application.
The library uses the DOM as its source of truth. It reads and writes ARIA attributes directly, with no per-component state and no framework dependency at runtime.
It’s ideal for teams building content-heavy or server-rendered pages who need real accessibility compliance at a near-zero runtime cost.
Features:
- Event delegation: A small set of global listeners handles every component on the page. There are no per-component instances, no memory allocations per element, and zero DOM queries at initialization.
- ARIA compliance: Every component follows WAI-ARIA Authoring Practices and targets WCAG 2.2 AA.
- Keyboard navigation: Arrow keys, Home, End, Enter, Space, and Escape all work as specified by ARIA patterns across every component.
- Framework-agnostic HTML API: Components activate via an ID naming convention. Any server-side framework — PHP, Rails, Django, or plain HTML — can render the markup and get full interactivity from a single script tag.
- Optional React wrappers: The
monochrome/reactpackage provides React components that generate the correct HTML structure and IDs. - Headless styling: No CSS ships with the library. You apply your own styles.
- Browser find-in-page preserved: The
hidden="until-found"attribute keeps collapsed content discoverable via Cmd+F in the browser. - Modern browser baseline: The library relies on the Popover API and
hidden="until-found". Supports all current major browsers.
How To Use It:
1. Install Monochrome with the package manager you prefer.
# Using npm npm install monochrome # Using pnpm pnpm add monochrome # Using bun bun add monochrome # Using yarn yarn add monochrome
2. Import the runtime once at your application’s entry point.
// Entry point: index.js, main.js, or app.js // This registers the global event listeners that power every component import "monochrome";
3. For projects that have no build step, use the CDN script tag:
<!-- Add this to your <head> or before </body> --> <!-- Works in PHP, Rails, Django, WordPress, or plain HTML files --> <script defer src="https://unpkg.com/monochrome"></script>
4. Create your own UI components. Monochrome identifies which elements to coordinate using a structured ID prefix system. You do not call any initialization function. The library reads these IDs on interaction and responds accordingly.
| Prefix | Role | Example ID |
|---|---|---|
mct: |
Trigger (the button or clickable element) | mct:collapsible:faq-1 |
mcc: |
Content (the panel that shows or hides) | mcc:collapsible:faq-1 |
mcr: |
Root container (for grouped components) | mcr:accordion:product-faq |
The third segment of the ID (e.g., faq-1) is your unique identifier. It links the trigger to its content panel. You choose it; just keep it consistent within a component pair.
<!-- Accordion Component -->
<div id="mcr:accordion:faq" data-mode="single">
<div>
<h3>
<button id="mct:accordion:q1" aria-expanded="false" aria-controls="mcc:accordion:q1">
What is monochrome?
</button>
</h3>
<div id="mcc:accordion:q1" role="region" aria-labelledby="mct:accordion:q1" aria-hidden="true" hidden="until-found">
A minimal component library...
</div>
</div>
<div>
<h3>
<button id="mct:accordion:q2" aria-expanded="false" aria-controls="mcc:accordion:q2">
How does it work?
</button>
</h3>
<div id="mcc:accordion:q2" role="region" aria-labelledby="mct:accordion:q2" aria-hidden="true" hidden="until-found">
Components are server-rendered...
</div>
</div>
</div>
<!-- Collapsible Component --> <button id="mct:collapsible:details" aria-expanded="false" aria-controls="mcc:collapsible:details"> Show more details </button> <div id="mcc:collapsible:details" aria-labelledby="mct:collapsible:details" aria-hidden="true" hidden="until-found"> This content is revealed when you click the trigger. </div>
<!-- Menu Component -->
<div id="mcr:menu:account">
<button type="button" id="mct:menu:account" aria-controls="mcc:menu:account" aria-expanded="false" aria-haspopup="menu">
Account
</button>
<ul role="menu" id="mcc:menu:account" aria-labelledby="mct:menu:account" aria-hidden="true" popover="manual">
<li role="presentation">Settings</li>
<li role="none"><button role="menuitem" tabindex="-1">Profile</button></li>
<li role="none"><button role="menuitem" tabindex="-1">Preferences</button></li>
<li role="separator"></li>
<li role="none"><button role="menuitem" tabindex="-1">Sign Out</button></li>
</ul>
</div>
<!-- Tabs Component -->
<div id="mcr:tabs:demo" data-orientation="horizontal">
<div role="tablist" aria-orientation="horizontal">
<button
role="tab"
id="mct:tabs:t1"
aria-selected="true"
aria-controls="mcc:tabs:t1"
tabindex="0"
>
Overview
</button>
<button
role="tab"
id="mct:tabs:t2"
aria-selected="false"
aria-controls="mcc:tabs:t2"
tabindex="-1"
>
Features
</button>
</div>
<div
role="tabpanel"
id="mcc:tabs:t1"
aria-labelledby="mct:tabs:t1"
aria-hidden="false"
tabindex="0"
>
Overview content...
</div>
<div
role="tabpanel"
id="mcc:tabs:t2"
aria-labelledby="mct:tabs:t2"
aria-hidden="true"
hidden="until-found"
tabindex="-1"
>
Features content...
</div>
</div>
5. If you use React, you can import the optional wrapper components. These components generate the correct HTML structure automatically.
// Accordion
import { Accordion } from "monochrome/react"
<Accordion.Root>
<Accordion.Item>
<Accordion.Header>
<Accordion.Trigger>What is monochrome?</Accordion.Trigger>
</Accordion.Header>
<Accordion.Panel>A minimal component library...</Accordion.Panel>
</Accordion.Item>
<Accordion.Item>
<Accordion.Header>
<Accordion.Trigger>How does it work?</Accordion.Trigger>
</Accordion.Header>
<Accordion.Panel>Components are server-rendered...</Accordion.Panel>
</Accordion.Item>
</Accordion.Root>
// Collapsible
import { Collapsible } from "monochrome/react"
<Collapsible.Root>
<Collapsible.Trigger>Show more details</Collapsible.Trigger>
<Collapsible.Panel>
This content is revealed when you click the trigger.
</Collapsible.Panel>
</Collapsible.Root>
// Menu
import { Menu } from "monochrome/react"
<Menu.Root>
<Menu.Trigger>Account</Menu.Trigger>
<Menu.Popover>
<Menu.Label>Settings</Menu.Label>
<Menu.Item>Profile</Menu.Item>
<Menu.Item>Preferences</Menu.Item>
<Menu.Separator />
<Menu.Item>Sign Out</Menu.Item>
</Menu.Popover>
</Menu.Root>
// Tabs
import { Tabs } from "monochrome/react"
<Tabs.Root defaultValue="overview">
<Tabs.List>
<Tabs.Tab value="overview">Overview</Tabs.Tab>
<Tabs.Tab value="features">Features</Tabs.Tab>
</Tabs.List>
<Tabs.Panel value="overview">Overview content...</Tabs.Panel>
<Tabs.Panel value="features">Features content...</Tabs.Panel>
</Tabs.Root>
The post Accessible UI Component Library for Vanilla JS & React – Monochrome appeared first on CSS Script.
Discover more from RSS Feeds Cloud
Subscribe to get the latest posts sent to your email.
