Accessible UI Component Library for Vanilla JS & React – Monochrome

Accessible UI Component Library for Vanilla JS & React – Monochrome
Monochrome is a lightweight, accessible UI component library that delivers keyboard navigation, ARIA attribute management, and focus handling through a single 2.2kB vanilla JavaScript runtime.

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/react package 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.

PrefixRoleExample 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.

Discover more from RSS Feeds Cloud

Subscribe now to keep reading and get access to the full archive.

Continue reading