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>
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.
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.
Related
I've been learning about the "for" attribute in HTML and what it does but I've stumbled upon a weird example that I've yet to understand
Code1
<input id="indoor" type="radio" name="indoor-outdoor">
<label for="indoor">Indoor</label>
Code2
<label for="loving"><input id="loving" type="checkbox" name="personality"> Loving</label>
<br>
<label><input type="checkbox" name="personality"> Loving</label>
I understand why "for" is used in the first block of code but I don't understand why the second code used "for" and "id" implicitly when it could've just worked fine without them.
Any help?
It is correct, that it works without it. But it is useful to connect the label with the input field. That is also important for the accessibility (e.g. for blind people, the text is read).
The browsers also allow you to click the labels and automatically focus the input fields.
For checkboxes this can be useful as well. But for these, you could also surround the checkbox-input like this:
<label>
<input type="checkbox"> I agree with the answer above.
</label>
In this case, the checkbox is automatically checked when you click on the text.
The surrounding of the inputs with a label works with every input field. But the text, that describes the input field, should always be inside it. That what for is for: When your HTML disallows the label-surrounding, you can use the for-attribute.
The the both following examples:
Simple stuctured:
<label>
Your Name:<br>
<input type="text"/>
</label>
Complex structure around input fields:
<div class="row">
<div class="col">
<label for="name">Your Name:</label>
</div>
<div class="col">
<input type="text" id="name" />
</div>
</div>
It could be used without "for" attribute, and it will be fine, according to docs.
This is just one option how to use "for" to omit confusing developers.
Anyway, in case of placing checkbox inside label, you can skip "for" and it will be fine.
<!-- labelable form-relation still works -->
<label><input type="checkbox" name="personality"> Loving</label>
"for" approach much preferable if you want to style it, f.e. using Bootstrap
<div class="form-check">
<input class="form-check-input" type="checkbox" value="" id="flexCheckDefault">
<label class="form-check-label" for="flexCheckDefault">
Default checkbox
</label>
</div>
To be able to use the label with the check box.
E.g., when rendered, click the label and it will toggle the check box ticked state.
Edit: Further to this, it allows putting the label anywhere on the page.
I currently write a user-interface for a search page on a local application. This search must have checkboxes to limit the scope of the search query. To make this functionality accesible I want to use "wai-aria"-Attributes.
So far my markup looks like this:
<div class="input-group">
<div class="checkbox-inline">
<input type="checkbox" id="check-bd-1">
<label for="check-bd-1">Band 1</label>
</div>
<div class="checkbox-inline">
<input type="checkbox" id="check-bd-2"></input>
<label for="check-bd-2">Band 2</label>
</div>
(... and so on...)
<p id="help-check-band" class="form-control-static">Helptext...</p>
</div>
I want to use a "aria-describedby"-Attribute to reference the helptext, identified by "help-check-band". This text is appropriate for each input of this group.
My question is: Where should I put the "aria-describedby"-attribute? Is it neccesary to put it on each <input>-element, or does it suffice to put it in the topmost div (with class "input-group")?
According to The Mozilla Dev-Network both ways seem to be possible. "aria-describedby" can be utilized by the container and the input elements. Since the attributes on the input-Element correspond directly with the functionality, this way seems to fit this case.
So I'v seen many tutorials and still haven't come up with a cohesive answer to this question: What's the correct/best way to mark up a form where I have a logical grouping of elements consisting of a label, control (input or select), and previous value, i.e. a single field?
I would like the CSS layout to place each grouping on a new horizontal line.
I've seen <div> wrappers, <br> tags, <ul>, <fieldset>, <tr>, and nothing at all (i.e. no markup tag, only CSS) used for this purpose.
Tables, aside from having a bad rep for doing form layout, aren't very flexible when the format of a row needs to vary. And br seems like a horrible idea (even though I've seen it in tutorials). I'm already using fieldset to create logical groupings of fields in a form, but I could always use two different classes if it's more semantically correct than div. The ul approach seems to be common by weird... the outer fieldset groups multiple fields, why do I need a ul that also groups them?
I really like the simplicity of the markup in this design: http://woork.blogspot.com/2008/06/clean-and-pure-css-form-design.html. But I'm having difficultly adapting the CSS to handle more complex fields, e.g. a select and input that logically belong together.
So in this example, what (if anything) to I wrap around field #1 and field #2 below?
<form .....>
<fieldset> <legend>Group 1</legend>
<!-- 'field #1' -->
<label for="newName">Name</label>
<input type="text" id="newName">
<!-- oldVal Filled in with Javascript or server-side script -->
<span class="oldVal" id="oldName">Old Name</span>
<!-- 'field #2' -->
<label for="newFood">Favorite Food</label>
<select id="newFood">
<option value="pizza">Pizza</option>
<option value="tacos">Tacos</option>
<option value="other">Other</option>
</select>
<input type="text" id="newFoodOther"> <!-- type here when 'other' is selected -->
<span class="oldVal" id="oldFood">Pizza</span>
</fieldset>
<fieldset> <legend> Group 2</legend>
<!-- more fields here -->
</fieldset>
</form>
What's the easiest to use for controlling the form layout, and what's the most semantically correct? And am I fortunate enough to have those be one and the same?
There is no single correct way to semantically mark up a form. Some methods are more flexible than others, but that doesn't mean you should choose them all the time. Sometimes a bit of quick markup is best.
For flexibility, I typically use a structure as follows:
<form>
<fieldset>
<legend></legend> <!-- optional -->
<label>
<span>Label Text</span>
<input type="..." />
</label>
<!-- repeat -->
<input type="submit" ... />
</fieldset>
</form>
Alternatively to help style with CSS I might use multiple labels:
<form>
<fieldset>
<label for="some-id-0">Label Text</label>
<label class="text-label">
<input type="text" id="some-id-0" />
</label>
<label for="some-id-1">Label Text</label>
<label class="password-label">
<input type="password" id="some-id-1" />
</label>
</fieldset>
</form>
But then I could separate this out into a list:
<form>
<fieldset>
<dl>
<dt>
<label for="some-id-0">Label Text</label>
</dt>
<dd>
<label class="text-label">
<input type="text" id="some-id-0" />
</label>
</dd>
<dt>
<label for="some-id-1">Label Text</label>
</dt>
<dd>
<label class="password-label">
<input type="password" id="some-id-1" />
</label>
</dd>
</dl>
</fieldset>
</form>
I find that adding more generic structural elements and classes tends to add flexibility to a certain degree, however you wont need any of that structure if you simply want a mad-lib form:
<form>
<p>
Hi, my
<label for="fullName">name</label>
is
<input type="text" id="fullName" name="fullName" placeholder="Full name" />
and I would like to request a copy of
<select id="publication" name="publication">
<option>Super Awesome Newsletter</option>
<option>Even more awesome-er newsletter</option>
<option>Lorem Ipsum weekly</option>
</select>
please send it to
<input type="temail" id="email" name="email" placeholder="email#example.com" />
</p>
<input type="submit" value="Thank you!" />
</form>
In the end the semantics revolve around how you want the form read. Unfortunately that means restructuring the form if significant changes are made.
"Semantically correct" applies to the HTML, not the CSS, and I'd say you already have that covered.
There's an infinite number of ways to style the form, of course, but one thing you can do without adding any extra markup is to make the labels into one "column" and the inputs into another:
label {
display: block;
float: left;
clear: left;
width: 150px;
}
input, select {
display: block;
float: left;
width: 150px;
}
http://jsfiddle.net/mblase75/ECmwH/
This leaves the problem of where to display your "oldVal" fields, but I think that's a matter of opinion.
What are the advantages of using the <fieldset> tag?
I don't really get what it is used for.
Forms are often broken up into various sets of fields.
The fieldset tag allows you to logically group sets of fields in order that your forms be more descriptive.
You'll also note that you can use the fieldset to style your forms and display those logical associations between fields.
Just like forms you find in the "real" world.
The "advantages" of using a fieldset are that they allow you to mark up your data (in this case a form) in the most semantic way available. Consider that placing your fields in a fieldset is more descriptive than placing your fields in a div. The div tells you nothing about the relationship between the fields, a fieldset tells you there is a relationship.
It's a similar principle to many of the new HTML5 tagsets. <footer> for example tells you more about the meaning of the data inside it compared to an ambiguous <div>.
If you take a look at the HTML5 spec for Developers:
http://developers.whatwg.org/forms.html#the-fieldset-element
The fieldset element represents a set
of form controls optionally grouped
under a common name.
(there's a lot more information if you follow the link)
Combined with the legend element, it allows you to easily do this, which is difficult to recreate without using fieldset/legend:
It allows you to group a set of related fields and give them a legend.
<fieldset>
<legend>Gender</legend>
<input type="radio" name="gender" id="male" value="male">
<label for="male">Male</label>
<input type="radio" name="gender" id="female" value="female">
<label for="female">Female</label>
<fieldset>
<fieldset>
<legend>Address</legend>
<label for="line1">Line 1</label>
<input name="address1" id="line1">
<label for="line2">Line 2</label>
<input name="address2" id="line2">
<label for="town">Town</label>
<input name="town" id="town">
<label for="country">country/label>
<input name="country" id="country">
</fieldset>
You group stuff together with it. Which is useful if you need to access things in it for CSS or JavaScript, and don't want to go through the hassle of assigning ID's to everything.
Also, the legend looks pretty good.
I have 4 radio buttons (A, B, C, D). When I click on the radio button A, there would be another 2 options - A1 and A2. The same will happen with the others. And if I choose D2, another 2 radio buttons would appear.
How can I do this in HTML?
HTML and CSS3-only version (Fiddle):
HTML for group "D" (other groups are similar)
<div>
<input type="radio" name="level0" value="D" id="D"/>
<label for="D">D</label>
<div class="sub1">
<div>
<input type="radio" name="level1" value="D0" id="D0"/>
<label for="D0">D0</label>
</div>
<div>
<input type="radio" name="level1" value="D1" id="D1"/>
<label for="D1">D1</label>
<div class="sub2">
<div>
<input type="radio" name="level2" value="D10" id="D10"/>
<label for="D10">D1-0</label>
</div>
<div>
<input type="radio" name="level2" value="D11" id="D11"/>
<label for="D11">D1-1</label>
</div>
</div>
</div>
</div>
</div>
CSS
.sub1, .sub2 { display: none; }
:checked ~ .sub1, :checked ~ .sub2 {
display: block;
margin-left: 40px;
}
If you want more radio buttons to appear when a certain one is selected, I would suggest not "nesting" them inside one another in the html. Have javascript display a hidden group or RBs when a one is selected.
Frankly, I think using radio buttons to make a select box appear would be much more user friendly, as its clear that you're selecting from a different group. Too many radio buttons always looks ugly.
Other problems with your code: id's should be unique, put the RB text beside the radio button as opposed to inside the tag, and avoid table based layout if possible. inline javascript and css should be avoided too, but as this is a code sample it actually makes it more readable. Oh, most importantly, you have the other buttons set to appear on onclick, so they won't go away if you unselect the RB :D
You can only use a specific id on one element in a document. You have to put different id's on each element and make them visible separately:
<input onclick="document.getElementById('extra1').style.visibility='visible';document.getElementById('extra2').style.visibility='visible';" type="radio" />Apple
<input type="radio" id="extra1" style="visibility:hidden" other choice here />
<input type="radio" id="extra2" style="visibility:hidden" other choice here />
#guffa I think I'll just modify your answer a bit. Put all the optional radio buttons inside a <div> element like this:
<input onclick='document.getElmentById("optional_buttons").style.display="block"' type="radio" />
<div id="optional_buttons" style="display: none;" >
optional radio buttons
</div>