Accessibility

Last updated on 2026-04-05

The Inventory Management Kit is built with WCAG AA accessibility as a baseline. Every component and page meets or exceeds these standards, using semantic HTML, ARIA attributes, and accessible interaction patterns throughout all 32 screens.

Every page includes a skip-to-content link as the first focusable element:

import { SkipLink } from "@/components/layout/skip-link"

<SkipLink />

The skip link is visually hidden until focused. It jumps the user directly to the #main-content landmark, bypassing the inventory sidebar and header navigation.

Color Contrast

All text meets WCAG AA contrast ratios:

  • Normal text (< 18px): minimum 4.5:1 contrast ratio
  • Large text (>= 18px bold or >= 24px): minimum 3:1 contrast ratio
  • UI components and states: minimum 3:1 against adjacent colors

The oklch color token system ensures contrast is maintained in both light and dark mode. The emerald/teal theme (hue 160) was specifically tuned so that primary-on-background and foreground-on-muted combinations pass AA thresholds.

Keyboard Navigation

All interactive elements are keyboard accessible:

  • Tab -- navigate between focusable elements in logical order
  • Shift+Tab -- navigate backwards
  • Enter/Space -- activate buttons, links, and toggles
  • Arrow keys -- navigate within menus, radio groups, tabs, and table rows
  • Escape -- close dialogs, sheets, popovers, and the command palette

Focus Indicators

Visible focus rings appear on all interactive elements using the --ring design token:

:focus-visible {
  outline: 2px solid var(--ring);
  outline-offset: 2px;
}

Focus Traps

Focus is trapped inside overlay components to prevent keyboard users from tabbing behind them:

  • Dialog -- product delete confirmation, PO cancel confirmation, adjustment confirmation
  • Sheet -- mobile sidebar navigation
  • Command -- global search command palette (Cmd+K)

When these components close, focus returns to the trigger element that opened them.

Table Keyboard Navigation

Data tables across the kit support keyboard interaction patterns:

  • Tab into the table, then Arrow keys to move between cells
  • Enter on a linked cell (product name, PO number) to navigate to the detail page
  • Space on a checkbox cell to toggle row selection
  • Escape to leave table navigation and return to the page

Screen Reader Support

Semantic HTML

All pages use proper HTML5 landmarks:

  • <header> for the app header
  • <nav> with aria-label for sidebar navigation and mobile navigation
  • <main> for primary content area
  • <aside> for the sidebar and detail panels
  • <section> with aria-label for dashboard widgets, report sections, and form groups
  • <time> with datetime attribute for order dates, delivery dates, and activity timestamps

ARIA Labels

Icon-only buttons include descriptive labels:

<Button aria-label="Search products">
  <Search className="size-4" />
</Button>

<Button aria-label="Switch to dark mode">
  <Moon className="size-5" />
</Button>

Live Regions

The LiveRegion component announces dynamic content changes to screen readers:

import { LiveRegion } from "@/components/a11y/live-region"

<LiveRegion message="Stock adjustment saved successfully" politeness="polite" />

Live regions are used for stock level updates, PO status changes, transfer confirmations, and form submission feedback.

Heading Hierarchy

Every page follows a strict heading hierarchy:

  • One <h1> per page (the page title)
  • <h2> for major sections
  • <h3> for subsections within those sections
  • No skipped heading levels

For example, the inventory dashboard uses <h1> for "Dashboard", <h2> for "Stock Overview", "Low Stock Alerts", and "Recent Activity" sections, and <h3> within each section as needed.

Touch Targets

All interactive elements meet the 44x44px minimum touch target size. The kit includes a .touch-target utility class:

.touch-target {
  min-width: 44px;
  min-height: 44px;
}

This class is applied to icon buttons in the app header (search, notifications, user menu), sidebar navigation items, table row action buttons, and form controls on mobile.

Reduced Motion

The kit respects the prefers-reduced-motion media query. When enabled:

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

This disables all animations including chart entrance animations, sidebar collapse/expand transitions, notification slide-ins, shimmer loading states, progress bar animations, and hover transforms on cards.

Status Indicators

Status information is never conveyed by color alone. The kit uses color plus icon plus text:

{/* Stock status uses icon + text + color */}
<AlertTriangle className="size-3 text-amber-500" />
<span className="text-amber-500">Low Stock</span>

{/* PO status uses icon + text + color */}
<CheckCircle className="size-3 text-chart-4" />
<span className="text-chart-4">Received</span>

The StatusBadge component combines color-coded badges with readable text labels (Draft, Submitted, Confirmed, Shipped, Received, Cancelled) so no information depends solely on color. Stock status indicators similarly pair color with descriptive text (In Stock, Low Stock, Out of Stock).

Form Accessibility

Forms across the kit follow accessibility best practices:

  • Labels associated with inputs via htmlFor/id
  • Error messages linked with aria-describedby
  • Required fields marked with visual indicators and aria-required
  • Invalid fields marked with aria-invalid for screen reader announcement
  • The product create/edit forms, PO create/edit forms, supplier forms, adjustment forms, and transfer forms all follow these patterns
  • Validation errors are announced to screen readers when forms are submitted

Data Table Accessibility

Data tables throughout the kit include:

  • <caption> elements describing the table content (e.g., "Product catalog with 48 items")
  • <th scope="col"> for column headers and <th scope="row"> where applicable
  • aria-sort on sortable column headers indicating current sort direction
  • Row selection checkboxes with aria-label describing the row content
  • Pagination controls with aria-label and aria-current="page" for the active page

Testing Recommendations

Tool Purpose
axe DevTools Automated accessibility scanning
VoiceOver (macOS) Screen reader testing
NVDA (Windows) Screen reader testing
Keyboard-only navigation Tab through every page
Lighthouse Accessibility audit score

Need a professional accessibility review? We run audits for Next.js and React apps starting at $499.