Skip to main content

Accessibility

Monochrome follows WAI-ARIA Authoring Practices and targets WCAG 2.2 Level AA compliance.

Standards Compliance

Every component implements the correct ARIA pattern:

Keyboard Navigation

All components are fully keyboard accessible. No mouse required.

Accordion

KeyAction
TabFocus next trigger
Shift + TabFocus previous trigger
Enter or SpaceToggle panel
ArrowDownFocus next trigger
ArrowUpFocus previous trigger
HomeFocus first trigger
EndFocus last trigger
Disabled accordion items are skipped during keyboard navigation.

Collapsible

KeyAction
TabFocus trigger
Enter or SpaceToggle panel
Collapsible follows the WAI-ARIA disclosure pattern. It does not support arrow key navigation (only accordions do).

Tabs

KeyAction
TabFocus active tab, then moves to panel
ArrowRight / ArrowLeftNavigate tabs (horizontal)
ArrowDown / ArrowUpNavigate tabs (vertical)
HomeFocus first tab
EndFocus last tab
Enter or SpaceActivate focused tab
Manual Activation: Monochrome uses manual activation (not automatic). Users must press Enter or Space to activate a tab after focusing it with arrow keys. This prevents accidental activation and reduces cognitive load.
KeyAction
TabClose all menus and move focus away
Enter or SpaceOpen menu (trigger) or activate item
ArrowDownNavigate to next item
ArrowUpNavigate to previous item
ArrowRightOpen submenu or navigate menubar
ArrowLeftClose submenu or navigate menubar
HomeFocus first item
EndFocus last item
EscapeClose current menu level
Letter keysTypeahead to item starting with that letter
Typeahead: Pressing letter keys jumps to the next item whose text starts with that letter.
Keyboard vs Mouse Behavior: When opened via keyboard (Enter/Space), menus focus the first item. When opened via mouse click, focus stays on the trigger. This follows WAI-ARIA best practices.

Focus Management

Monochrome uses roving tabindex for arrow key navigation:
  • Only one element is in the tab order (tabindex="0")
  • All other navigable elements have tabindex="-1"
  • Arrow keys move focus without affecting the tab order
  • This creates a single tab stop for groups of related controls

How It Works

<button id="mct:accordion:faq-1" tabindex="0">Question 1</button>
<button id="mct:accordion:faq-2" tabindex="-1">Question 2</button>
<button id="mct:accordion:faq-3" tabindex="-1">Question 3</button>

ARIA Attributes

Monochrome manages all ARIA attributes automatically. You don’t set them manually.

Accordion

  • aria-expanded="true|false" — Trigger state
  • aria-controls="{panel-id}" — Links trigger to panel
  • aria-labelledby="{trigger-id}" — Labels panel with trigger
  • aria-disabled="true" — Disabled state (not HTML disabled)
  • role="region" — Panel landmark

Tabs

  • role="tablist" — Tab container
  • role="tab" — Tab buttons
  • role="tabpanel" — Content panels
  • aria-selected="true|false" — Active tab
  • aria-controls="{panel-id}" — Links tab to panel
  • aria-labelledby="{tab-id}" — Labels panel with tab
  • aria-orientation="horizontal|vertical" — Arrow key direction
  • role="menu" — Menu container
  • role="menubar" — Menubar container
  • role="menuitem" — Standard item
  • role="menuitemcheckbox" — Toggle item
  • role="menuitemradio" — Radio item
  • aria-haspopup="menu" — Trigger has submenu
  • aria-expanded="true|false" — Menu open state
  • aria-checked="true|false" — Checkbox/radio state
  • aria-disabled="true" — Disabled item
Monochrome uses aria-disabled="true", not the HTML disabled attribute. This is intentional:
  • Disabled menu items render as <span> to prevent click bubbling
  • aria-disabled keeps elements in the accessibility tree
  • Screen readers announce disabled state

Screen Reader Support

All components are tested with:
  • NVDA (Windows / Firefox)
  • JAWS (Windows / Chrome)
  • VoiceOver (macOS / Safari)
  • Narrator (Windows / Edge)

Announcements

  • Triggers announce their expanded state: “Question 1, button, collapsed”
  • Tabs announce selection: “Home, tab, 1 of 3, selected”
  • Menu items announce role: “New File, menu item”
  • Checkbox items announce state: “Bold, menu item checkbox, checked”

Find-in-Page Support

Monochrome uses hidden="until-found" instead of display: none. This preserves browser find-in-page (Cmd+F / Ctrl+F).

How It Works

  1. User presses Cmd+F and searches for text inside a collapsed panel
  2. Browser finds the text and fires a beforematch event
  3. Monochrome’s core listens for beforematch and automatically opens the containing component
  4. Browser scrolls to and highlights the found text
hidden="until-found" is a Baseline 2024 feature supported in all modern browsers.

Color Contrast

Monochrome is headless, so contrast is your responsibility. Follow WCAG 2.2 Level AA:
  • Normal text: 4.5:1 contrast ratio
  • Large text: 3:1 contrast ratio (18pt+ or 14pt+ bold)
  • UI components: 3:1 contrast ratio for interactive elements

Testing Tools

Touch and Mobile Support

All keyboard interactions work on mobile via touch:
  • Touch targets: Ensure buttons are at least 44×44px (WCAG 2.2 Target Size)
  • Menu hover intent: Safety triangles are disabled for touch (pointerType === "touch")
  • Scrolling: Menus close on scroll (unless scrolling inside the menu itself)

Disabled State

Disabled items are:
  • Marked with aria-disabled="true"
  • Skipped during keyboard navigation
  • Announced by screen readers as “disabled”
  • Non-interactive (cannot be clicked)
<Accordion.Item disabled>
  <Accordion.Trigger>Disabled Section</Accordion.Trigger>
  <Accordion.Panel>Content</Accordion.Panel>
</Accordion.Item>

Best Practices

  1. Provide visible focus indicators — Users must see where keyboard focus is
  2. Use semantic heading levels — Accordion headers default to <h3>, but you can change via the as prop
  3. Label regions properly — All panels are linked to their triggers via aria-labelledby
  4. Test with keyboard only — Unplug your mouse and navigate your entire UI
  5. Test with a screen reader — Enable VoiceOver (macOS) or NVDA (Windows) and navigate
  6. Avoid manual ARIA — Let Monochrome manage attributes. Manual overrides can break functionality
  7. Maintain focus order — Don’t use tabindex values other than 0 and -1

WCAG 2.2 Checklist

Level A (Required)

  • 1.1.1 Non-text Content — Images have alt text (your responsibility)
  • 2.1.1 Keyboard — All functionality available via keyboard
  • 2.1.2 No Keyboard Trap — Users can navigate away with Tab or Escape
  • 4.1.2 Name, Role, Value — All ARIA attributes correctly set

Level AA (Target)

  • 1.4.3 Contrast (Minimum) — 4.5:1 text, 3:1 UI (your responsibility)
  • 2.4.7 Focus Visible — Focus indicator always visible (your responsibility)
  • 2.5.8 Target Size (Minimum) — 44×44px touch targets (your responsibility)
  • 3.2.4 Consistent Identification — Components behave predictably

Additional Resources

Build docs developers (and LLMs) love