Support for Marking Radio Buttons Required, Invalid

The required set of radio buttons. The white whale to many a developer who is trying their darnedest to ensure they are conveyed accessibly while not also making it sound like every individual radio button must be toggled.

A radio pulled from a 1960s era car dashboard showing the buttons for moving between pre-set stations.
1961 Cadillac Wonderbar dashboard radio by Nicholas Lucien (cropped). CC BY 2.0.

Part of the challenge is that the required attribute is not valid on a <fieldset> (which maps to the group role). This is a rare case where ARIA is the only technically valid approach, specifically the radiogroup role with aria-required.

What if browsers and screen readers weren’t that strict?

In many cases they aren’t. Some of the more common browser/SR pairings will announce required on a <fieldset> the same as they announce aria-required on a radiogroup.

On the other hand, aria-invalid has no native HTML equivalent. It is also invalid on a <fieldset> without the radiogroup role but most pairings don’t seem to care.

I have been getting the question about which combo supports which structure for so long that I opted to make it into a post. If you asked me that question and I sent you here, then I have justified this Monday night.

Following are results from testing six different examples; a baseline you can use for your own testing. No validation happens on any of these forms. The buttons are there simply for completeness (and a place to park your focus).

Testing Results

This is not meant to indicate if the browser / screen reader combination is adhering to the specification. Instead the table only indicates if the required and/or invalid property / state is conveyed.

The browser and screen reader combinations preceded by an asterisk represent the generally recommended pairings for the platform (which is similar to the most common pairings).

Browser / screen reader support for each method
Browser / SR 1. required on <fieldset> 2. aria-required on <fieldset> 3. aria-required, aria-invalid on <fieldset> 4. required with radiogroup Role 5. aria-required with radiogroup Role 6. aria-required, aria-invalid with radiogroup Role 7. Uses aria-readonly with radiogroup Role
* Chrome / JAWS Yes 1 Yes 1 Yes 1,2 Yes 1 Yes 1 Yes 1,2 No 3
Firefox / JAWS No 3 Yes 1 Yes 1,2 No 3 Yes 1 Yes 1,2
IE11 / JAWS Yes 1 Yes 1 No 1,3 Yes 1 Yes 1 No 1,3,4
Chrome / NVDA Yes 1 Yes 1 Yes 1,2 Yes 1 Yes 1 Yes 1,2
* Firefox / NVDA No 3 Yes 1 Yes 1,2 No 3 Yes 1 Yes 1,2 No 3
IE11 / NVDA Yes 1 Yes 1 Yes 1,2,4 Yes 1 Yes 1 Yes 1,2,4
* Edge / Narrator Yes 1 Yes 1 No 1 Yes 1 Yes 1 No 1 No 3
* Safari / macOS / VO Yes 1 Yes 1 Yes 1,2 Yes 1 Yes 1 Yes 1,2 No 3
Chrome / macOS / VO Yes 1 Yes 1 Yes but problematic 1,2,5 Yes 1 Yes 1 Yes but problematic 1,2,5
Firefox / macOS / VO No 3 Yes 1 No 1,3 No 3 Yes 1 No 1,3
* Chrome / TalkBack No 3 No 3 No 3 No 3 No 3 No 3 No 3
Firefox / TalkBack No 3 No 3 No 3 No 3 No 3 No 3
* Safari / iPadOS / VO Yes 1 Yes 1 Yes 1,2 Yes 1 Yes 1 Yes 1,2 No 3
  1. announces as “required”.
  2. announces as “invalid”.
  3. property or state not exposed.
  4. announces aria-describedby content as part of accName.
  5. does not announce aria-describedby content.

Considering the more common pairings (indicated with * in the table), only Firefox / NVDA honors some technical purity by ignoring required on <fieldset> but allowing the other constructs. TalkBack is just broken.

The Tests

I only put together six tests. You can build on these for your own use.

1. Uses required on <fieldset>

This is an invalid construct. The required attribute is not allowed on <fieldset>.

Carb

2. Uses aria-required on <fieldset>

This is an invalid construct. The aria-required attribute is not allowed on <fieldset>.

Meat

3. Uses aria-required, aria-invalid on <fieldset>

This is an invalid construct. Neither aria-required nor aria-invalid is allowed on <fieldset>.

Protein

This is an error message.

4. Uses required with radiogroup Role

This is an invalid construct. The required attribute is not allowed on a radiogroup role.

Vegetable

5. Uses aria-required with radiogroup Role

This is valid HTML and ARIA. Please bear in mind that the radiogroup role is strictly for cases where only one item in a set can be selected at a time (so not checkboxes).

Fruit

6. Uses aria-required, aria-invalid with radiogroup Role

This is valid HTML and ARIA. Please bear in mind that the radiogroup role is strictly for cases where only one item in a set can be selected at a time (so not checkboxes).

Spice

This is an error message.

7. Uses aria-readonly with radiogroup Role

The post is not about read-only controls, but might as well give it a pass while I am here. No enforcement of the read-only state happens; I am simply concerned with how it is exposed.

Sauce

My testing suite:

Standalone Examples

These radio button examples exist as a CodePen that you can try outside of the context of my site, also in a cruft-free debug mode.

See the Pen Testing Required and Invalid Radios by Adrian Roselli (@aardrian) on CodePen.

More Info

These results can change over time as browsers and screen readers update. Other content on your own page may interact in ways this does not cover. These are minimal HTML examples so be prepared to test with constructs that use lots of nested HTML. This does not account for non-<fieldset> constructs. None of this applies to checkboxes, nor should it. Please see a physician if the errors last more than 4 hours.

At the time of posting I made the column headers in the table vertical in an effort to address a bug in Chrome. Because I had set minimum widths on the column headers, even inside the scrolling container it caused horizontal scrollbars in Chrome. I don’t know if this is a better approach, but am confident people will speak up for what they don’t like. Instead of littering the comments, feel free to ping me on Twitter or through the contact form.

Thanks to Sarah Higley for helping make my intro less confuddling.

Update: 17 November 2022

Since I first recorded the results, I am happy to note some positive changes. Windows Narrator has moved from being completely broken to almost two-thirds of the way there. Safari with VoiceOver on iPadOS has improved as well, now announcing the aria-describedby value.

Out of an abundance of curiosity, I added a new test. I was curious how aria-readonly with radiogroup would announce. It does not. I also only tested the common browser and screen reader pairings.

7 Comments

Reply

Great work, very useful!

Given that Talkback petulantly refuses to work with any of the combinations, do you think it would make more sense to just add explicit text to the fieldset (i.e., “Fruit (required)”) instead of relying on ARIA here? Takes care of sighted users at the same time.

In response to James C. Reply

Yup!

Reply

I second James’ comment: thank you! Terrific work. You’re doing a real service for developers who want to get this stuff “right”, or at least as accessible as reasonably possible, given the differences in browser behavior.

Peter Weil; . Permalink
Reply

There’s a “This is bad you should feel bad” in

https://adrianroselli.com/2022/02/support-for-marking-radio-buttons-required-invalid.html#R6

I don’t think that’s intended, indeed this checker says it is good:

https://validator.w3.org/nu/#textarea

In response to Chris Leighton. Reply

Chris, that example (6. Uses aria-required, aria-invalid with radiogroup Role) opens with This is valid HTML and ARIA.

I think you misinterpreted my fake error message wording, “This is bad you should feel bad”, as a statement about the HTML construct in use. As such, I changed the poor wording to read “This is an error message” instead. Hopefully my cavalier error message will not confuse anyone else.

Reply

Retested Chrome/ Talkback with same results as documented in the table above:
* Chrome v. 109.0.5414.86
* Android v. 13
* Talkback v. 13.1

Andrew Nevins; . Permalink
In response to Andrew Nevins. Reply

Animated thumbs-up emoji.

Leave a Reply to James C Cancel response

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>