Closed ebollens closed 12 years ago
When it comes to general form markup, we seem to have two general approaches:
control-group
, control-label
, controls
, etc.I'm certainly in favor of approach (1) instead of approach (2) because it is more semantic. This is the approach that Bootstrap takes, as opposed to the one in Foundation 3 and HTML 5 Boilerplate. However, I find Bootstrap's semantics way overboard in the amount of writing it takes to accomplish a very simply set of markup. The big question is thus: how do we reduce the semantics so that they feel easy to work with? This is what I'm currently looking into.
On another note, one of the things we're going to need to do for this is polyfill HTML5 form types. So far, I'm looking primarily at this library to accomplish it: http://afarkas.github.com/webshim/demos/index.html ... It is built on top of jQuery and Modernizr, two libraries that are already packaged with WebBlocks, so it makes a reasonable candidate.
From a semantics point of view, you can style a form control and label in two ways:
The label represents a caption in a user interface. The caption can be associated with a specific form control, known as the label element’s labeled control, either using for attribute, or by putting the form control inside the label element itself.
However, this article assets that the for
/id
method is preferable because of browser support:
http://www.paciellogroup.com/blog/2011/07/html5-accessibility-chops-form-control-labeling/
The article however kind of disagrees with the latest version of the text cases: http://www.html5accessibility.com/tests/form-labels.html
Essentially, it's legitimate to do either of these:
<label>Label text<input></label>
<label for="someId">Label text</label><input id="someId">
The question becomes which one is more workable. I'm inclined to agree with Bootstrap that in most cases the label
extricated from the input is better, because it lets you attach additional elements as well such as help text that isn't part of the label but is related. They can be logically arranged by placement inside of some container element. This arrives us back at the Bootstrap-like semantics:
<div>
<label for="someId">Label text</label>
<input id="someId">
<p>Some other text</p>
</div>
Bootstrap is more verbose about these control groups, namely assigning classes all over the place and wrapping the controls and paragraph in another div element. While this will make it easy to apply @extend
, I don't think it's necessary in our implementation to explicitly state things like control-group
and controls
, as it can be implied by context what is going on here.
There is one problem with this, however, and that is the input types checkbox
and radio
. Often, it makes sense to give each of these a label for what they represent such as:
<label><input type="checkbox"> What the checkbox is</label>
You might want to have an entire checkbox group, though, and then the question becomes how to reasonably denote the difference in these two types of labels (such as in forms where the label appears in a left column to a right column that is the label content, but where you want the label on the checkbox to appear to the right of the checkbox. Bootstrap, because it has verbose class semantics, gets around this simply by defining a special class on the label. I think we'll have to do about the same thing, but then the question becomes what, besides a label, can be used as the left portion to denote what a group of checkboxes is called.
I was thinking about maybe using the section
element as the outer container:
The section element represents a generic section of a document or application. A section, in this context, is a thematic grouping of content, typically with a heading.
Sounds cool, huh? Unfortunately, there's a catch given this statement:
A general rule is that the section element is appropriate only if the element’s contents would be listed explicitly in the document’s outline.
It wouldn't be bad that our form controls showed up in the outliner as subsets of the form, but alas that requires each control "group" to have a header element - which isn't a label
and thus this isn't viable.
Another thing I've thought about is trying to use the meta-pattern of the group as I describe in #121. However, I don't think this is a good idea either, because that ticket already talks about allowing input groups (although how does a label refer to a set of inputs? It can't!) I'm thus inclined to throw this idea out the window as well, because I'd rather provide group support where a set of inputs each gets a label over it when using .group > input
.
This is just me putting some of my thoughts out there in words... Hoping to solidify an actual strategy later today.
Another interesting, although a bit unconventional approach, creates a list for each fieldset: http://24ways.org/2009/have-a-field-day-with-html5-forms
I actually like this approach because it creates a structure for the form that isn't just div
- when you're filling out a form, in a way what you are doing is filling out a list of information, so this could be another approach to defining the items of the form. It adds more structure than we see in Foundation and Boilerplate, without the verbosity of all those control-X
classes.
One possible approach would thus be:
<form>
<ul>
<li>
<label for="in1">..</label>
<input id="in1">
</li>
<li>
<label for="t1">..</label>
<textarea id="t1"></textarea>
<p>Some help text for t1</p>
</li>
</ul>
<fieldset>
<legend>..</legend>
<ul>
<li>
<div class="label">..</div>
<div class="controls">
<label><input type="checkbox"> Checkbox</label>
<label><input type="checkbox"> Checkbox</label>
</div>
</li>
</ul>
</fieldset>
</form>
A more conventional approach that still contains each label/input would be:
<form>
<div>
<label for="in1">..</label>
<input id="in1">
</div>
<div>
<label for="t1">..</label>
<textarea id="t1"></textarea>
<p>Some help text for t1</p>
</div>
<fieldset>
<legend>..</legend>
<div>
<div class="label">..</div>
<div class="controls">
<label><input type="checkbox"> Checkbox</label>
<label><input type="checkbox"> Checkbox</label>
</div>
</div>
</fieldset>
</form>
This is lighter-weight but could be a little challenging to implement possibly because of the fact that a div
is being used in so many different ways.
It might also be possible to do away with the containing classes for each controls altogether:
<form>
<label for="in1">..</label>
<input id="in1">
<label for="t1">..</label>
<textarea id="t1"></textarea>
<p>Some help text for t1</p>
<fieldset>
<legend>..</legend>
<div class="label">..</div>
<div class="controls">
<label><input type="checkbox"> Checkbox</label>
<label><input type="checkbox"> Checkbox</label>
</div>
</fieldset>
</form>
I don't like this last approach, though, because it doesn't create a semantic separation of each set of controls. If it were always just a single input, one would think this okay, but the problem accrues because one may seek to have a set of checkboxes linked semantically.
@atsengucla @loganfranken @ccheung thoughts on what might be a good approach here?
hmmmm. @ebollens I feel this is one issue we should get feedback from @chris4ucla on. Forms are critical to accessibility and if there are no issues with access I'm inclined for the list approach. From the monolithic CMS product perspective lists are great -- any type of structure that has a predictable pattern we can work with better -- as there's something we can use for predictable hooks and for incrementing off. But I'm curious what happens when you nest forms in a list for accessibility.
We tested the technique of wrapping an input in a label without explicit for/id attributes some time ago. And our results were that it did NOT work, at least not all the time or consistently. It's likely were were using JAWS 12, which is still very common in use. The html5accessibility page only indicates testing with JAWS 13. So I believe we need to actually use the for/id attributes.
The fieldsets are the right way to do groups of checkboxes/radio buttons (with the for/id attributes). Having the input before the label is expected.
I don't think adding list items into the markup would cause a problem. We can do some testing to confirm.
@chris4ucla any update on accessibility considerations?
I'm also sliding this back to 1.0.04 as it slipped from my dev in this milestone given that I was at Educause all week this week.
For the moment, I've settled on this variant:
<form class="form"> <!-- optionally also class "horizontal" -->
<!-- other elements, including containing elements -->
<div class="control">
<label></label> <!-- optional, kind of -->
<p></p> <!-- optional help text -->
<input> <!-- optional input item -->
<p></p> <!-- optional help text -->
</div>
<!-- other elements, including containing elements -->
</form>
Basically, I'm going for a high level of flexibility:
div.control
is a direct parent for the form controls. By naming it, we can place it anywhere within a broader set of markup, such as within a panel. This is something that an ol
or ul
based approach cannot achieve. form.form.horizontal
is a class that lays out elements with label on the left and everything else on the right, where the things in the right are displayed in DOM order (and label
can be placed anywhere within div.controls
but must be a direct child).This is just a first pass to start defining some semantics, and only a first commit at that. I will continue to add and tweak until I get something pinned down that achieves that balance between too convoluted of code and not understandable enough by semantics.
Going to need a box-sizing polyfill as well...
Patrick is out at a conference this week. We had been testing a few options, but I still want to confirm a few things with him. With regard to the
for help text. That's not ideal. If the help text is not within the label element, it will not be picked up as a screen reader user goes from input to input. It will be skipped. The only way they would notice it is if they read through the content of the page.
@chris4ucla suppose I have the following:
<div class="control">
<label for="phone">Phone Number</label>
<input type="tel" id="phone" name="phone_number">
<p>You are allowed to enter phone numbers of the format 555-5555, 555-555-5555, 1-555-555-5555, +555-555-5555</p>
</div>
A label is said to be a caption for a form control. A caption is an element that provides a descriptive name for the targeted element. Therefore, the label is clearly "Phone Number" and not "You are allowed to enter phone numbers of the format...", as the latter is a constrain on the type of input allowed, not a description of what exactly the element represents. Even if they were both valid, how would we capture both at the same time? We run into a conundrum: we have a primary label for an element but also some additional text that describes how the element should be formatted. It appears that most frameworks out there don't try to tackle this.
Luckily, however, ARIA seems to give us an easy way out: http://www.w3.org/TR/WCAG20-TECHS/ARIA1
Based on this, I'd suggest that these are correct semantics:
<div class="control">
<label for="phone">Phone Number</label>
<input type="tel" id="phone" name="phone_number" aria-describedby="phone_help">
<p id="phone_help">You are allowed to enter phone numbers of the format 555-5555, 555-555-5555, 1-555-555-5555, +555-555-5555</p>
</div>
Thoughts?
The problems with forms and accessibility usually has to do with screen readers. Specifically not being able to match up the content on the page with the appropriate fields. That's why the label element is used. While the aria attribute should better expose the help note to the screen reader user, I'm not sure that it would allow them to know that the help note specifically refers to that input. This particular example is rather straight forward. If there's only one input that's labeled as phone on the page, then it's pretty obvious that the help would refer to that phone field. But in other cases the content of the help might not so easily identify itself. Without an explicit connection between the help text and the input, the help text could easily be mistaken as belonging to another input on the page, most likely the one right before or right after the one it's supposed to go with. I'd like to get Patrick's feedback when he returns.
I usually put the help text within in it's own span inside the label. But if the help text is long, then that is not so good.
oh, wait. now i see the explicit link. I think this might work. I still want to get Patrick's feedback.
I'd like to avoid placing the next in the label for two reasons:
label
attribute (see Techniques for WCAG 2.0: H65) but we might still want to embed help text even if a label
is not used.label
attribute.So yeah, if this explicit use of aria-describedby
works in Patrick's testing, then we should be set.
I may also experiment with transparently applying the aria-describedby
attribute through a Javascript library. This would improve accessibility without placing any undue burden on the markup designer to actually assign the aria-describedby
attribute. The only problem I'm running into right now in trying to figure out how to do this particular transparent transform is the fact that you could in theory associate multiple inputs within a single div.control
.
@chris4ucla et al., I have committed an initial version of the form implementation. Please see the demo/entity/form.html
document to review the prototype layout as it stands currently. Open a new issue if any problems are encountered.
We should develop a form strategy. Bootstrap's does not necessarily make sense, so I will start by researching other options.