Accessibility / Foundations / Accessibility in engineering

Foundations

Accessibility in engineering

Semantic structure, focus management, ARIA used correctly and sparingly, and how we test with real assistive technology.

A design can be fully accessible and still ship broken if the markup doesn’t carry its meaning. This page covers what we build into components, how we test, and where ARIA helps versus where it just adds risk. It applies to frontend engineering, the component library, and QA, against a conformance target of WCAG 2.2 AA.

This page applies to work built on Granite, our established component library across the IFS product offering, and on Helix, our system for next-generation applications. Helix was designed with accessibility as a starting requirement, not a later pass, so new product work should build on it where it’s the right fit rather than defaulting to Granite out of habit.

Semantic HTML first

The first rule of ARIA is not to use ARIA. A native <button>, <a>, or <table> gets keyboard behaviour, focus handling, and assistive technology support for free; a <div> re-built to look like one has to re-implement all of it correctly, forever, across every browser and screen reader combination. We reach for a native element before reaching for a role.

ARIA: precise, minimal, tested

Where a native element genuinely can’t express the interaction — a combobox, a tree grid, a live region for background status — we follow the WAI-ARIA Authoring Practices Guide (APG) pattern exactly, including its keyboard interaction model, rather than inventing our own. An ARIA role or attribute that doesn’t match the actual behaviour of the component is worse than no ARIA at all, because it promises assistive technology something the component doesn’t deliver.

Situation We do
Custom dropdown, tree, tab set Follow the matching WAI-ARIA APG pattern exactly, including keys.
Status message after an async action Announce via a polite aria-live region; never alert() for non-blocking status.
Icon-only button Accessible name via aria-label, matched to visible tooltip text.
Decorative image or icon aria-hidden="true" or empty alt="" — never a filename as alt text.

Focus management

Opening a dialog moves focus into it and traps it there until closed; closing it returns focus to the control that opened it. Route changes in single-page views move focus to the new view’s heading, so a screen reader user isn’t left listening to a page that visually changed under them. Focus is never removed from the page entirely, and never silently reset to the top on unrelated re-renders.

Forms and validation, in code

Every input has a programmatically associated <label>. Validation errors are linked to their field with aria-describedby and the field is marked aria-invalid="true"; error summaries at the top of a long form use a live region so they’re announced on submit, since visible alone isn’t enough for someone using a screen reader.

Testing, layered

  • Automated — axe-core in CI on every pull request; a new violation on a changed page blocks merge. Automated tools catch an estimated 30–40% of issues — a pass is a floor, not a certificate.
  • Manual keyboard pass — tab through the whole flow with the mouse unplugged: order, visibility, and no traps.
  • Screen reader pass — NVDA + Chrome and VoiceOver + Safari at minimum before release of a new or materially changed component.
  • Assistive technology user testing — for major features, scheduled through the process described on the Accessibility in our process page.

Component-level Definition of Done

A Granite or Helix component isn’t done until it has: a visible focus indicator that meets 3:1 contrast against its background, full keyboard operability without a mouse, a verified accessible name and role exposed to assistive technology, respect for prefers-reduced-motion, and a passing axe-core scan with zero known violations at release. This checklist is enforced in code review, not left to a separate accessibility team to catch later.