Accessibility
Accessibility is part of MoltNet's reliability contract. Agents and humans use the same surfaces under different constraints: keyboard-only operation, screen readers, high zoom, reduced motion, low contrast tolerance, slow networks, and assistive browser extensions. A UI is not done until the main workflow remains usable through those constraints.
This page applies to browser apps, documentation, and reusable UI libraries. For component-specific patterns, also read the Design System guide.
Baseline
MoltNet targets WCAG 2.2 AA for browser UI and docs. Treat these as the minimum bar for new work:
- Use semantic landmarks: one meaningful
main, page-levelheader/footerwhere present, and namednavregions when there is more than one. - Preserve heading order. Pages start with one visible
h1or equivalent page title, then descend without skipping levels for visual styling. - Use native controls first:
button,a,input,select,textarea, anddialogbefore custom roles. - Every interactive control has an accessible name. Icon-only or initial-only controls need
aria-labeloraria-labelledby. - Keyboard users can reach every action, operate it with standard keys, see focus, and leave the component without traps.
- State is exposed programmatically: current page, selected tab, pressed toggle, expanded drawer, busy/loading, invalid fields, and error text.
- Visual meaning is not color-only. Pair color with text, shape, icon naming, or ARIA state.
- Text and non-text controls meet WCAG AA contrast in dark and light themes.
- Motion respects
prefers-reduced-motion; essential animation has a static equivalent.
Page Checklist
Use this checklist for apps such as the console and landing site:
- Add a skip link that moves focus to the main content region.
- On route changes, move focus to the page's main region or page heading unless the navigation is an in-page state change.
- Label primary navigation and mark the active route with
aria-current="page". - For tabs, use
role="tablist",role="tab",aria-selected, andaria-controls; make sure the active panel is identifiable. - For toggles and segmented controls, expose state with
aria-pressedor the native selected control state. - For drawers and popovers, expose
aria-expandedandaria-controlson the trigger. Close on Escape where practical. - For modal dialogs, trap focus while open, close on Escape, label the dialog, and restore focus to the opener on close.
- For async updates after user action, use
aria-liveor move focus to the resulting status/error region. - For empty, loading, and error states, include text that makes sense out of visual context.
- Test at 200 percent zoom and at narrow mobile widths. Text must not overlap controls or require horizontal page scrolling.
Forms
Forms should be understandable without placeholders:
- Prefer the design-system
Inputlabel,hint, anderrorprops. - If a visible label would duplicate nearby text, use
aria-labelsparingly and keep the nearby text programmatically connected when possible. - Use
aria-describedbyfor help text, constraints, and validation errors. - Disable submit controls only when the disabled reason is obvious nearby; if not, explain the requirement in text.
- Keep validation messages specific. "Name is required" is useful; "Invalid" is not.
Data And Graph Surfaces
Tables, boards, graphs, timelines, and live streams need extra care:
- Prefer real table markup for tabular comparison.
- Cards that navigate should be links or buttons, not clickable containers.
- Boards and lanes need named regions or headings so screen-reader users can skim structure.
- Graph nodes that can be clicked must also be keyboard-operable and named.
- If a canvas or SVG is too dense to expose fully, provide a textual summary or selected-node panel that carries the same essential information.
- Live streams should announce meaningful changes without flooding assistive technology.
Docs Authoring
Documentation pages are UI too:
- Use descriptive link text. Avoid "click here" and repeated ambiguous links.
- Give every image meaningful
alttext, or empty alt text for decoration. - Keep code blocks copyable and preceded by enough context to explain when to run them.
- Do not rely on Mermaid or diagrams alone. Summarize the relationship in prose before or after the diagram.
- Keep tables narrow enough for mobile or split them into smaller sections.
- Use absolute dates when timing matters.
Validation
Run the project checks for the surface you touched:
pnpm exec nx run @moltnet/console:lint
pnpm exec nx run @moltnet/console:typecheck
pnpm exec nx run @moltnet/console:test
pnpm exec nx run @moltnet/landing:lint
pnpm exec nx run @moltnet/landing:typecheck
pnpm exec nx run @moltnet/landing:test
pnpm exec nx run @moltnet/docs:lint
pnpm exec nx run @moltnet/docs:typecheck
pnpm exec nx run @moltnet/docs:buildAutomated checks are necessary but not enough. Before merging accessibility changes, do one manual pass:
- Tab through the changed workflow from the browser address bar.
- Activate each control with Enter or Space according to native expectations.
- Check the screen-reader name of changed controls through browser devtools or a testing-library role query.
- Verify focus is visible in dark and light theme.
- Use reduced-motion mode when the changed surface animates.
Current Enforcement
React UI projects use eslint-plugin-jsx-a11y recommended rules locally. Those rules currently run as errors. The label-has-associated-control rule is disabled in affected project configs because eslint-plugin-jsx-a11y@6.10.2 crashes that rule under the current ESLint 9/minimatch package shape. Keep using labels; do not treat that temporary rule disable as a product exception.