Are form elements description text in the wrong place?

We encourage users to post events happening in the community to the community events group on https://www.drupal.org.
jbjaaz's picture

I've been working with some forms and something occurred to me. The "description" text always appears after the the form element throughout drupals UI.

Password
[input box]
Password must be between 8 and 10 characters and only include letters and numbers.

I don't have a lot of experience with screen readers, but the visitor would have the "help" text read to them after they've entered a password correct? Wouldn't this be a nuisance of sorts because they are getting the hint after the fact?

Is this a valid concern? I don't want to investigate a fix if this really isn't a problem.

Comments

Partial solutions

wdmartin's picture

I've just run some experiments using JAWS (5.0, which is out of date now), Opera 9.12's Voice module, Safari's Speech service and FireVox. I whipped up a simple test page specifying an alt attribute for the input element, thus:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head>
  <title>Forms accessibility test</title>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>
<body>
<form action="f" target="f">
<label for="Password">Password:</label>
<input type="text" alt="Password must be between 8 and 10 characters and only include letters and numbers." id="Password" />
</form>
</body>
</html>

According to the specs, the alt attribute is only supposed to be used on input elements where type="image". But validators don't complain about it. Results:

JAWS 5: did not read the alt text
FireVox: did not read the alt text
Opera Voice: did not read the alt text
Safari: did not read the alt text

So then I tried using a title attribute instead of an alt attribute, but they didn't read that, either.

JAWS 5: did not read the title text
FireVox: did not read the title text
Opera Voice: did not read the title text
Safari: did not read the title text

I did however come up with a partial solution, based on putting some hidden text in the label element. Here:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head>
  <title>Forms accessibility test</title>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <style type="text/css">
    .accessible { position: absolute; margin-left: -9999px; }
  </style>
</head>
<body>
<form action="f" target="f">
<label for="Password">Password: <span class="accessible">Password must be between 8 and 10 characters and only include letters and numbers.</span></label>
<input type="text" id="Password" />
</form>
</body>
</html>

The span giving the details does not render in any visual browser I tested in. In the example I've set its position to absolute to remove it from the usual document flow, and then moved it off the screen. Note that the margin-left value must be negative - if you set it to 9999px instead of -9999px, then visual browsers will sprout a horizontal scroll bar and show the content if you scroll over to it, which is not the desired behavior.

Then I ran my tests again:

JAWS 5: read the hidden text
FireVox: read the hidden text
Opera Voice: read the hidden text
Safari: read the hidden text

So there's a partial solution. Unfortunately, it has the effect of removing the details for visual users, who of course also need it. But if we put the visual version back in place after the input element, then our aural users have to listen to the details twice.

I had hoped that the aural stylesheet properties in CSS 2 might be of use, so I ran some more tests.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head>
  <title>Forms accessibility test</title>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <style type="text/css">
    .accessible { position: absolute; margin-left: -9999px; }
  </style>
<style type="text/css" media="aural">
    .silent { speak: none; }
   </style>
</head>
<body>
<form action="f" target="f">
<label for="Password">Password: <span class="accessible">Password must be between 8 and 10 characters and only include letters and numbers.</span></label>
<input type="text" id="Password" /><span class="silent">Password must be between 8 and 10 characters and only include letters and numbers.</span>
</form>
</body>
</html>

In theory, the "silent" span should not be read. Results:

JAWS 5: read both
FireVox: read both
Opera Voice: read the hidden text, but not the silent text
Safari: read both

JAWS is the most popular screen reader, without question, and so the lack of support there pretty much kills that solution. I haven't tested more recent versions of JAWS yet, but I don't have much hope, since their FAQ on CSS specifies that they don't support the "media" attribute in JAWS 7.10 or higher, but instead follow Internet Explorer's rendering of it. (And their support for Firefox is flaky at best.) As for Opera Voice, well, it's not really designed for accessibility purposes. It's more for people who can see to highlight a chunk of text they want read aloud. (Note: by default, Opera Voice can be triggered in only two ways: by selecting text and then saying "Opera Speak" into a microphone, or by selecting text and then pressing V for voice.) Safari's speech service is similar.

In short, we can provide that kind of contextual detail to users with screen readers, but we can't effectively prevent them from getting it twice while still retaining the information for sighted users. If we could work out some way of including the textual information in the label tag but repositioning it with respect to its input element, then that might work. It'd be hard to do it in a universally applicable way, though. I'll have to think about it some more.

A simple solution

jbjaaz's picture

Nice. Thanks for the screen reader testing wdmartin.

So, it turns out that customizing the location of the help text is really easy. Its just a matter of overriding the theme_form_element function.

function mytheme_form_element($element, $value) {
  $output  = '<div class="form-item">'."\n";
  $required = !empty($element['#required']) ? '<span class="form-required" title="'. t('This field is required.') .'">*</span>' : '';

  if (!empty($element['#title'])) {
    $title = $element['#title'];
    if (!empty($element['#id'])) {
      $output .= ' <label for="'. $element['#id'] .'">'. t('!title: !required', array('!title' => filter_xss_admin($title), '!required' => $required)) ."</label>\n";
    }
    else {
      $output .= ' <label>'. t('!title: !required', array('!title' => filter_xss_admin($title), '!required' => $required)) ."</label>\n";
    }
  }
 
  if (!empty($element['#description'])) {
    $output .= ' <div class="description">'. $element['#description'] ."</div>\n";
  } 

  $output .= " $value\n";

  $output .= "</div>\n";

  return $output;
}

Cool!

authoring accessible content

access@drupal.org's picture

Does anyone know of an authoring tool or editor that can be intergrated that will help author accessible forms or tables. At this time the only way possible I can see is to edit the HTML.

Unfortunately, no

Cliff's picture

This is one of those situations where the accessibility issues that arise can be recognized and addressed only by a human. There are tools that can help you recognize potential issues in code you've already generated (for example, the WAVE toolbar), but even those can, at best, say, "A human should look at this table (or form) and see if it really is coded properly."

For example, the first column of a table should be identified as header elements (th) if, in fact, the information in that column is the header for the corresponding row. WAVE can't tell whether that's the case, so it can't tell you whether "td" should be "th" or vice versa.

But shouldn't this be the behavior we want in core?

mgifford's picture

So, I've taken the work suggested here in a themable function and applied it here - http://drupal.org/node/405360

If you want this behavior by default, please give a +1 to it. Would be great to have some support indicating why this is a best practice.

Mike

OpenConcept | CLF 2.0 | Podcasting