How to group form inputs accessibly without a fieldset?
Asked Answered
C

3

14

Problem: Grouping form elements

I have an HTML form, where in few places a single control is composed of several inputs. One example is a group of radio buttons.

I'd like to group those inputs and it's label explicitly, so that the screen readers would also (in addition to the visual representation by aligning them on a single line) be able to understand and announce this relationship.

For example, let's say I have a control like this:

<div class="control">
  <div class="control-label">Type</div>
  <div class="control-inputs">
    <input type="radio"
           name="type"
           value="a"
           id="type-a" />
    <label for="type-a">A</label>

    <input type="radio"
           name="type"
           value="b"
           id="type-b" />
    <label for="type-b">B</label>
  </div>
</div>

Standard solution problems: Fieldset styling issues

fieldset element and it's child legend seem to be made exactly for that (used in the example below).

The problem is that fieldset and legend elements can't be styled like normal elements (some discussion about it) and nowadays other than in Firefox it's impossible to align them on a single line using Flexbox, which my layout requires.

<fieldset class="control">
  <legend class="control-label">Type</legend>
  <div class="form-inputs">
    <input type="radio"
           name="type"
           value="a"
           id="type-a" />
    <label for="type-a">A</label>

    <input type="radio"
           name="type"
           value="b"
           id="type-b" />
    <label for="type-b">B</label>
  </div>
</fieldset>

Question: Is there some other way?

That makes me wonder if there is some accessible way to group several form controls other than using fieldset element?

Possible solution: role="group"?

There is a "group" role (used in the example below), which could be added to a simple div and it looks like it might do the job, but nowhere is stated clearly that it is the functional equivalent to using a fieldset. And if it does, then how do I mark an element of this group to serve as an equivalent of legend?

<div role="group"
     class="control">
  <div class="control-label">Type</div>
  <div class="control-inputs">
    <input type="radio"
           name="type"
           value="a"
           id="type-a" />
    <label for="type-a">A</label>

    <input type="radio"
           name="type"
           value="b"
           id="type-b" />
    <label for="type-b">B</label>
  </div>
</div>
Color answered 15/1, 2018 at 15:14 Comment(0)
A
17

Basically you have already answered your question in the Possible Solution section (btw, as a blind person, I'm just impressed how you styled your question with headings!). You missed one tiny and simple thing, the aria-label attribute:

<div role="group" class="control" aria-label="Type">

Note: this will be invisible on screen, it is a screen-reader only solution. If however you want to make it visible, do the following using the aria-labelledby attribute instead:

<div role="group" class="control" aria-labelledby="pseudolegend">
<div id="pseudolegend" class="style-it-like-a-legend">Type</div>
[...]
</div>

The pseudolegend may be a span or even a p, of course, if you find it more appropriate.
A quick and dirty local test I made showed that, at least with JAWS and Chrome, there is no difference between a fieldset and a div with aria-label.

Astragalus answered 15/1, 2018 at 22:59 Comment(2)
Oh, sure, aria-labelledby and aria-label! It seems to be just what I need. Thanks!Color
So sad we need to craft a unique id for this instead of selecting in a local context.Were
C
7

Note: For radio button groups in particular you can use role=radiogroup. Also, in order for the semantics of a group or radiogroup to be expressed to screen reader users an accessible name for the grouping element is required.

Chimborazo answered 17/1, 2018 at 7:4 Comment(2)
The "accessible name for the grouping element" is the name for the whole radiogroup and in this case it should be provided by aria-label/aria-labelledby. Am I understanding it right?Color
@Robert exactly :-)Chimborazo
S
2

You can also use display: contents on the fieldset, so it will not affect the structure of rendered elements and the fieldset will be ignored.

.control {
  display: contents;
}
<fieldset class="control">
  <div>
    <input type="radio"
           name="type"
           value="a"
           id="type-a" />
    <label for="type-a">A</label>

    <input type="radio"
           name="type"
           value="b"
           id="type-b" />
    <label for="type-b">B</label>
  </div>
</fieldset>

Note: display: contents property is still partially supported, please check it on Can I use before implementing.

Superannuation answered 18/8, 2023 at 12:1 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.