Categories: CSSScriptWeb Design

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.

Table of Contents

Toggle

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:

Sponsored
<!-- 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.

rssfeeds-admin

Share
Published by
rssfeeds-admin

Recent Posts

US and Israeli Attacks on Iran Violate International Law

THE HAGUE, Netherlands (AP) — As U.S. and Israeli forces pounded Iran, and Tehran and its…

1 hour ago

Only 1 in 4 Americans Support Trump’s War on Iran, Reuters/Ipsos Poll Shows

Americans don’t trust President Donald Trump when it comes to foreign policy, a Reuters/Ipsos poll…

1 hour ago

The $9 Joyroom Car Adapter Adds Wireless Bluetooth Audio and USB Charging Ports to Your Old Car

If you own an old car without Bluetooth and you're looking for a cheap and…

1 hour ago

Alienware Still Has One of the Lowest Prices on an RTX 5080 Equipped Prebuilt Gaming PC

2026 has already seen surges in the cost of RAM and GPUs. Unfortunately, this also…

1 hour ago

Iran war drives gas price uncertainty ahead of busy summer season

A gas pump is seen in a vehicle on Nov. 26, 2025, in Austin, Texas.…

2 hours ago

Iran war drives gas price uncertainty ahead of busy summer season

A gas pump is seen in a vehicle on Nov. 26, 2025, in Austin, Texas.…

2 hours ago

This website uses cookies.