Skip to main content
All Docs
FeaturesMaking Tax DigitalUpdated March 25, 2026

Accessibility: Screen Reader Error Announcements on Forms (A11Y-20)

Accessibility: Screen Reader Error Announcements on Forms

Release: v1.0.446 · Audit item: A11Y-20 · WCAG criteria: 3.3.1, 1.3.1

Overview

As of v1.0.446, all five forms in the application correctly announce validation errors to screen reader users. Previously, when a form submission failed or real-time validation fired, errored inputs carried no programmatic indication of their invalid state, meaning users of assistive technologies (NVDA, JAWS, VoiceOver) heard nothing when tabbing back to a field that needed correction.

This release resolves audit item A11Y-20 and brings those forms into full compliance with WCAG 2.1 success criteria:

  • 3.3.1 Error Identification (Level A) — errors are identified and described in text
  • 1.3.1 Info and Relationships (Level A) — structure conveyed visually is also available to assistive technologies

Affected Forms

FormLocation
Sign-in/sign-in
Sign-up/sign-up
Profile settings/dashboard/settings (profile section)
Organisation settings/dashboard/settings (org section)
Feedback widgetGlobal (available on all dashboard pages)

How It Works

aria-invalid

Every input that can enter an error state now sets aria-invalid={true} when an error is present and aria-invalid={false} when it is not. This attribute is the standard signal assistive technologies use to determine whether a field needs attention.

<input
  aria-invalid={!!submitError}
  aria-describedby={submitError ? "profile-form-error" : undefined}
  ...
/>

aria-describedby

When an error is active, aria-describedby is set to the id of the error message container. Each form uses a unique ID so there is no ambiguity across multiple forms on the same page:

FormError container ID
Sign-insignin-form-error
Sign-upsignup-form-error
Profile settingsprofile-form-error
Organisation settingsorg-form-error
Feedback widgetfeedback-error

When there is no error, aria-describedby is set to undefined (omitted from the DOM) so the browser does not maintain a stale reference.

Password field on sign-up

The password input always references signup-password-hint via aria-describedby, ensuring the requirements paragraph is announced regardless of error state. The hint text changes dynamically:

StateAnnounced text
No password entered"Must be at least 10 characters. We'll check your password against known data breaches to keep your account secure."
Password too weak"Please choose a stronger password (at least 10 characters with a mix of letters, numbers, or symbols)."
Password acceptable(empty — no redundant announcement)

When a submit error also exists, aria-invalid is set to true and aria-describedby switches to signup-form-error so the server-side error message is read instead.

Feedback widget textarea

The feedback textarea previously had no associated <label>, making it unlabelled for screen reader users. A visually-hidden label (Feedback message) has been added using the sr-only utility class:

<label htmlFor="feedback-message" className="sr-only">
  Feedback message
</label>
<textarea
  id="feedback-message"
  aria-invalid={!!error}
  aria-describedby={error ? "feedback-error" : undefined}
  ...
/>

The error container in this widget has also been upgraded to include role="alert" so that errors are announced immediately when they appear, consistent with all other forms.

No Breaking Changes

All changes are purely additive HTML attribute changes. No visual appearance, behaviour, API, or data model has been altered.