Simple inline error message pattern

Error messages can be problematic to convey consistently to all users across browsers and assistive technology (AT). Using simple HTML, with a little ARIA polyfil magic if you want to get fancy, you can robustly associate error messages with controls and ensure that users get the message every time.

The issue

  • You want to display a message to users in the case where they have not filled in a form field correctly.
    • You want the error to be announced by screen readers when the invalid field is focused.
    • You don’t wan’t any delay between the field getting focus and the error message being announced.
    • You want it to work in as many browser and AT combinations as is possible.

The really simple pattern

Add the error message as a child of the label element associated with an input.

It is really robust because the error message, when added, becomes part of the accessible name for the control:

Non-error state of input type=text:

accessible name: “pootish”

Error state of input type=text:

accessible name: “pootish ERROR – fill it in sucker!”

See the Pen ZQLeev by steve faulkner (@stevef) on CodePen.

A pretty simple pattern

This pattern is almost as robust as the previous, except that it relies on some ARIA magic to polyfil the lack of implementation support for multiple labels. While browsers support the activation behaviour for multiple labels (you can click on any label associated with a control via for/id). Only Firefox currently exposes the correct accessible name.
Using a separate label for the error message provides more flexibility in (CSS) decoration and positioning of the message. It results in the same accessible names for the non-error and error states as the really simple pattern.

See the Pen rxLERr by steve faulkner (@stevef) on CodePen.

Bugs filed

As mentioned above, browsers mostly don’t implement the deriving of an accessible name from multiple label elements, so have filed some bugs, so in the future the use of aria-labelledby, in this case, will not be needed.


Categories: Technical

About Steve Faulkner

Steve was the Chief Accessibility Officer at TPGi before he left in October 2023. He joined TPGi in 2006 and was previously a Senior Web Accessibility Consultant at vision australia. Steve is a member of several groups, including the W3C Web Platforms Working Group and the W3C ARIA Working Group. He is an editor of several specifications at the W3C including ARIA in HTML and HTML Accessibility API Mappings 1.0. He also develops and maintains HTML5accessibility and the JAWS bug tracker/standards support.


Michiel Bijl says:

WebKit nightly builds have the same issue with multiple labels. Have filled a bug here:

Neil Osman says:

Are these patterns better than toggling an aria-describedby on the required input (which points to an aria-hidden element id)?

Šime Vidas says:

In the second demo, aria-invalid is set on the error label (instead of the input). Is that ok?

Steve Faulkner says:

Hi Šime,
no, that’s just my crappy coding, fixed, now on input.
Note: the JavaScript and CSS is for demo purposes only, I am not and probably never will be good at these 🙂

Steve Faulkner says:

Hi Neil, the ‘really simple’ pattern is the most robust as it does not require any ARIA, it makes use of label element behaviour that has been implemented in browsers since I was young (i.e. a long time). The second demo does make use of ARIA, but it confines its usage to aria-labelledby with multiple id references which has better support in legacy (i.e. older IE) than aria-describedby with multiple id references. The other thing to note is that in certain AT (i.e. VoiceOver) there is a delay before aria-describedby content is announced, this is viewed by some as problematic, as a result a whole new ARIA property has been proposed: aria-errormessage. Related github issue discussion.

Patrick H. Lauke says:

Just as a quick side note, in case anybody is wondering where HTML5’s native validation messages/bubbles fit into all this: they’re really badly (un)supported at the moment – see

Evidently both demos had aria-invalid set on the label, now the first one remains to be corrected 🙂

Steve Faulkner says:

Doh! fixed now, thanks