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.
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 / 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 |
- announces as “required”.
- announces as “invalid”.
- property or state not exposed.
- announces
aria-describedby
content as part of accName. - 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>
.
2. Uses aria-required
on <fieldset>
This is an invalid construct. The aria-required
attribute is not allowed on <fieldset>
.
3. Uses aria-required
, aria-invalid
on <fieldset>
This is an invalid construct. Neither aria-required
nor aria-invalid
is allowed on <fieldset>
.
4. Uses required
with radiogroup
Role
This is an invalid construct. The required
attribute is not allowed on a radiogroup
role.
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).
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).
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.
My testing suite:
- Firefox 95–97 / NVDA 2021.2
- Firefox 107 / NVDA 2022.3.2
- Chrome 97–100 / JAWS 2021–2022
- Chrome 107 / JAWS 2023
- Edge 97–98 / Narrator / Windows 10
- Edge 107 / Narrator / Win11 22H2
- Safari 15.2 / VoiceOver / macOS 12.1
- Safari 16.1 / VoiceOver / macOS 12.6.1
- Safari / VoiceOver / iPadOS 15.1
- Safari 16.1 / VoiceOver / iPadOS 16.1
- Chrome 96–97 / TalkBack 9.1 / Android 12
- Chrome 107 / TalkBack 13 / Android 13
- Firefox 96–98 / TalkBack 9.1 / Android 12
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.
9 Comments
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 .Yup!
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.
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:
In response to .Chris, that example (6. Uses
aria-required
,aria-invalid
withradiogroup
Role) opens withThis 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.
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
In response to .Animated thumbs-up emoji.
Good work but why not just put the word ‘required’ in the legend description for everyone to read?
In response to .Yup!
Leave a Comment or Response