Getting Drupal to emit screen-reader friendly dates is a pain in the butt. It can, however, be done. Here's a detailed account of my efforts on that score, complete with tests in two screen readers (including MP3s for your listening pleasure), some analysis, and a detailed walk through of customizing the code for a DATE element.
Let's look at an example. Here's the PHP for a fairly standard date input in Drupal's Forms API, from a project I've been working on:
<?php
$form['td']['rush']['rush-date'] = array(
'#type' => 'date',
'#title' => t('Needed by'),
'#required' => false,
'#default_value' => array(
'day' => format_date(time(), 'custom', 'j'),
'month' => format_date(time(), 'custom', 'n'),
'year' => format_date(time(), 'custom', 'Y'),
),
);
?>Drupal 6.9 renders that with the following HTML (reformatted and abbreviated for legibility):
<div class="form-item" id="edit-rush-date-wrapper">
<label for="edit-rush-date">Needed by: </label>
<div class="container-inline">
<div class="form-item" id="edit-rush-date-day-wrapper">
<select name="rush-date[day]" class="form-select" id="edit-rush-date-day">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
[...]
<option value="31">31</option>
</select>
</div>
<div class="form-item" id="edit-rush-date-month-wrapper">
<select name="rush-date[month]" class="form-select" id="edit-rush-date-month">
<option value="1">Jan</option>
[...]
<option value="12">Dec</option>
</select>
</div>
<div class="form-item" id="edit-rush-date-year-wrapper">
<select name="rush-date[year]" class="form-select" id="edit-rush-date-year">
<option value="1900">1900</option>
<option value="1901">1901</option>
<option value="1902">1902</option>
[...]
<option value="2050">2050</option>
</select>
</div>
</div>
</div>I've put together a bare bones test case. Here are some samples of how it's read by two screen readers:
As the demographics of screen reader use make clear, the most common screen reader out there is JAWS from Freedom Scientific. However, I do not have a purchased copy handy at this time, and the evaluation version of JAWS does not permit its use in testing code. Therefore I will not be testing with it.
There are some differences in how FireVox and NVDA read the sample. You'll note that FireVox silently omits the "Needed by" label. The reason for that is in the code:
<label for="edit-rush-date">Needed by: </label>
The FOR attribute of this label associates it with the input in the document which has the ID "edit-rush-date". Unfortunately, there is no such input in the document. I asked Charles Chen, the developer of FireVox, about this a while back. In essence, he explained that he'd decided a LABEL element with no associated form element shouldn't be read at all, because it would erroneously lead the listener to believe that the form has more inputs than it actually does.
NVDA treats it differently -- it goes ahead and reads the orphaned label. Both NVDA and FireVox are affected by the other problem, which is that the three individual inputs comprising the date picker lack labels. In the FireVox sample, you'll hear that it reads the actual date pickers as:
Select box: One
Select box: Jan
Select box: Nineteen hundred
And NVDA reads it as:
Needed By
Combo box, collapsed submenu: One
Combo box, collapsed submenu: Jan
Combo box, collapsed submenu: Nineteen hundred
In both cases it's not clear from the audible description what the select boxes are actually for. FireVox's omission of the label makes it even less clear in that screen reader than in NVDA, but neither one is very obvious. It would help somewhat to have a more recent year as the default value, of course, which didn't occur to me till after I'd begun testing.
But even then, the screen reader user is left to infer the purpose of the form controls based on the types of information stored in them -- a one or two-digit integer for the day, an abbreviated month name for the month, and a four digit integer for the year. The order of the fields may get in the way of its understandability as well, depending on your cultural background. An American screen reader user would probably expect dates inputs to be ordered Month-Day-Year, while a British screen reader user would expect Day-Month-Year. In the absence of explicit labels for all three parts of the date, blind visitors are left to guess, and the cultural difference in date order just make it harder.
The root of the problem is one of hierarchy. A date picker like this one is supposed to yield just one form value -- the date -- but consists of three discrete form inputs for the day, month, and year. The discrete form inputs each require a label. That part is easy, like this:
<div class="form-item" id="edit-rush-date-wrapper">
<span>Needed by: </span>
<div class="container-inline">
<div class="form-item" id="edit-rush-date-day-wrapper">
<label for="edit-rush-date-day">Day: </label>
<select name="rush-date[day]" class="form-select" id="edit-rush-date-day">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
[...]
<option value="31">31</option>
</select>
</div>
<div class="form-item" id="edit-rush-date-month-wrapper">
<label for="edit-rush-date-month">Month: </label>
<select name="rush-date[month]" class="form-select" id="edit-rush-date-month">
<option value="1">Jan</option>
[...]
<option value="12">Dec</option>
</select>
</div>
<div class="form-item" id="edit-rush-date-year-wrapper">
<label for="edit-rush-date-year">Year: </label>
<select name="rush-date[year]" class="form-select" id="edit-rush-date-year">
<option value="1900">1900</option>
<option value="1901">1901</option>
<option value="1902">1902</option>
[...]
<option value="2050">2050</option>
</select>
</div>
</div>
</div>The labels can be hidden easily enough with CSS -- .container-inline label { position: absolute; left: -999em; } would do it, though it would be preferable to add a more specific class to the HTML like class="form-item-date" to avoid applying the rule to other contexts. Adding explicit labels this way makes it a lot easier to interpret the purpose of the form controls, as you can hear:
But in order to be fully intelligible, the group as a whole needs a label too, and that label needs to be associated with all three form elements. It is possible to write code containing multiple labels for a single form input:
<label for="edit-rush-date-day">Needed by: </label>
<label for="edit-rush-date-day">Day: </label>
<select name="rush-date[day]" class="form-select" id="edit-rush-date-day">
<option value="1">1</option>
[...]
<option value="31">31</option>
</select>And, in fact, this is fully conformant with the HTML 4.01 standard, which says that "More than one LABEL may be associated with the same control by creating multiple references via the for attribute."[ref] The XHTML standard does not alter that.
However, screen reader support for multiple labels is variable. Given the above code, FireVox will speak both labels, but NVDA will only speak the first one.
Even if screen readers all supported multiple labels perfectly, though using multiple labels wouldn't solve the problem. The HTML specification requires that each label be associated with exactly one form control. The FOR attribute takes an ID, not a class. So in order to label each of the three select boxes, we would need three copies of the "Needed By" label, one for each of the three form elements:
<label for="edit-rush-date-day">Needed by: </label>
<label for="edit-rush-date-month">Needed by: </label>
<label for="edit-rush-date-year">Needed by: </label>
<label for="edit-rush-date-day">Day: </label>
<select name="rush-date[day]" class="form-select" id="edit-rush-date-day">
<option value="1">1</option>
[...]
<option value="31">31</option>
</select>
[...]That's obviously a bad solution, partly because it bloats the code, but also because it requires us to hide two of those duplicate labels from sighted visitors, which bloats the code even further. Great.
The natural HTML elements to use in this situation are FIELDSET and LEGEND elements. They were explicitly designed to group related sets of form controls together and to provide a label for the whole group in a screen-reader friendly way. Something like this works nicely:
<fieldset class="form-date">
<legend>Needed By:</legend>
<label for="edit-rush-date-day">Day: </label>
<div class="container-inline">
<select name="rush-date[day]" class="form-select" id="edit-rush-date-day">
<option value="1">1</option>
[...]
<option value="31">31</option>
</select>
<label for="edit-rush-date-month">Month: </label>
<select name="rush-date[month]" class="form-select" id="edit-rush-date-month">
<option value="1">Jan</option>
[...]
<option value="12">Dec</option>
</select>
<label for="edit-rush-date-year">Year: </label>
<select name="rush-date[year]" class="form-select" id="edit-rush-date-year">
<option value="1900">1900</option>
<option value="1901">1901</option>
[...]
<option value="2050">2050</option>
</select>
</div>
</fieldset>This is fully intelligible in both screen readers:
The next thing to take care of is its appearance. The default styling for a FIELDSET/LEGEND combo is much too visually complex for just a date picker. Fortunately, it's not terribly difficult to make it look just like most other Drupal form items -- a bold label one line above the input. You can see a test case, using this CSS:
/* Remove the visual apparatus of the fieldset. /
.form-date {
border: 0;
margin: 0;
padding: 0;
background: none;
}
/ Hide the labels for the individual elements from sighted visitors. /
.form-date label {
position: absolute;
left: -999em;
}
/ Hide the labels for the individual elements from sighted visitors. /
.form-date legend { font-weight: bold; }
/ Add a little extra space between the legend and the parts, for legibility. */
.form-date .inline-container { margin-top: 5px; }That renders acceptably in all four major browsers (screenshots). All that's left is to make Drupal emit the correct HTML and CSS to achieve this effect. Now, from here on in I'm going to assume that you're developing a module, because that's what I'm doing. Some of this can be replicated on the theme layer; other bits of it can't as far as I know. I'll indicate which is which.
First up, let's get some labels in place for the individual elements in the date. The Drupal function responsible for that is expand_date(), which takes the array of values provided in the #default_value index of the form array that defines the structure of the form. All it really does is automatically create SELECT elements in Drupal's Forms API notation. To make it spit out an appropriately formatted label, we'll need to override that function.
The first step is to make a copy of the stock expand_date() function into your module and rename it. My module is named ds_ticket, so the function will be ds_ticket_expand_date(). It actually only needs a single line added to make it produce the labels -- I've marked that with a comment below. Thus:
<?php
function ds_ticket_expand_date($element) {
// Default to current date
if (empty($element['#value'])) {
$element['#value'] = array('day' => format_date(time(), 'custom', 'j'),
'month' => format_date(time(), 'custom', 'n'),
'year' => format_date(time(), 'custom', 'Y'));
}
$element['#tree'] = TRUE;
// Determine the order of day, month, year in the site's chosen date format.
$format = variable_get('date_format_short', 'm/d/Y - H:i');
$sort = array();
$sort['day'] = max(strpos($format, 'd'), strpos($format, 'j'));
$sort['month'] = max(strpos($format, 'm'), strpos($format, 'M'));
$sort['year'] = strpos($format, 'Y');
asort($sort);
$order = array_keys($sort);
// Output multi-selector for date.
foreach ($order as $type) {
switch ($type) {
case 'day':
$options = drupal_map_assoc(range(1, 31));
break;
case 'month':
$options = drupal_map_assoc(range(1, 12), 'map_month');
break;
case 'year':
$options = drupal_map_assoc(range(1900, 2050));
break;
}
$parents = $element['#parents'];
$parents[] = $type;
$element[$type] = array(
'#type' => 'select',
'#title' => t($type), // <--- Add a label for each one.
'#value' => $element['#value'][$type],
'#attributes' => $element['#attributes'],
'#options' => $options,
);
}
return $element;
}
?>Once that's in place, we'll modify the original definition of the form field to call our version of expand_date() instead of the stock one. Here's that form field definition again:
<?php
$form['td']['rush']['rush-date'] = array(
'#type' => 'date',
'#title' => t('Needed by'),
'#required' => false,
'#default_value' => array(
'Day' => format_date(time(), 'custom', 'j'),
'Month' => format_date(time(), 'custom', 'n'),
'Year' => format_date(time(), 'custom', 'Y'),
),
'#process' => array('ds_ticket_expand_date'), // <----- Make it use our custome function.
);
?>Save the .module file, upload, and voila -- labels on all the individual dates. I don't know if you could accomplish the same thing from a theme's template.php; I've never tried. If it's possible, it would probably require using hook_form_alter().
Next up, we need to re-write the theming to make it generate the fieldset and legend code. The stock theming is handled by theme_date(). We'll need to override that with a custom function. The first step is to register a custom theming function using hook_theme(). Like this:
<?php
/**
* Implementation of hook_theme();
* Lists the theme functions and templates used by the module, along with their arguments (where applicable).
*/
function ds_ticket_theme() {
$themes = array();
// Theme functions for the form.
$themes['ds_ticket_date'] = array('arguments' => array());
return $themes;
}
?>In this case, it's just a function, not a template file, and we don't need to pass any unusual arguments to the new function. The new function itself must have the same name as the index in hook_theme (here that's 'ds_ticket_date'), only with 'theme_' on the front, so the full name of the function is 'theme_ds_ticket_date'. If you're working from a template rather than a module, you can override the stock theme_date() simply by creating a function in your template.php file named either 'phptemplate_theme_date()' or 'YourThemeNameHere_theme_date()'. You may need to clear the Drupal cache in order to make it recognize your new function, which can be done by going to Administer --> Site Configuration --> Performance and clicking the "Clear Cached Data" button. If you're going to be doing that a lot, though, you'll probably want to install the Devel module, which adds a new block to your site with a very handy "Empty Cache" link.
In my module, I created the new function by copying and pasting the stock function in and changing the function name, like this:
<?php
function theme_ds_ticket_date($element) {
return theme('form_element', $element, '<div class="container-inline">'. $element['#children'] .'</div>');
}
?>As you can see, it's a really basic function. And, as yet, it's not actually doing anything. We've created the new theme function, and registered its existence with Drupal, but we haven't specified that the form element should use it yet. That's done by adding a #theme index, thus:
<?php
$form['td']['rush']['rush-date'] = array(
'#type' => 'date',
'#title' => t('Needed by'),
'#required' => false,
'#default_value' => array(
'Day' => format_date(time(), 'custom', 'j'),
'Month' => format_date(time(), 'custom', 'n'),
'Year' => format_date(time(), 'custom', 'Y'),
),
'#process' => array('ds_ticket_expand_date'),
'#theme' => array('ds_ticket_date'), // <--- Make it use our custom theme function
);
?>Now it should finally use our theme function. Let's make it produce a fieldset instead of the usual code.
<?php
function theme_ds_ticket_date($element) {
$title = $element['#title'];
$fieldset = '<fieldset class="form-date">';
$fieldset .= "<legend>$title</legend>";
$fieldset .= '<div class="container-inline">';
// Build the day, month, and year select boxes.
$children = element_children($element);
foreach($children as $c){ $fieldset .= drupal_render($element[$c]); }
$fieldset .= '</div>';
$fieldset .= '</fieldset>';
return $fieldset;
}
?>This seems pretty straightforward, but it took a while to work out. In the stock theme_date() function, it just threw the element at theme() and passed it a value of $element['#children'] -- but when I examined that in my own version, it didn't exist. I believe theme_date() actually gets called twice (or more) in the process of building a date, but I'm not certain. Because Drupal relies so heavily on calling functions through call_user_func(), the execution flow can be rather opaque.
Anyway, I studied drupal_render() a bit. Since $element['#children'] didn't exist, I built it myself using element_children() to retrieve the children, and drupal_render() to render them as normal.
Another problem I ran into was that Drupal invariably wrapped the whole fieldset in another DIV containing a malformed LABEL. It was apparently calling theme_date() again after my own theme function ran, and adding an extraneous wrapped. I still don't know why it was doing this, or the proper way of making it stop. What eventually fixed it for me was manually marking the form element as "printed" in the initial form definition, thus:
<?php
$form['td']['rush']['rush-date'] = array(
'#type' => 'date',
'#title' => t('Needed by'),
'#required' => false,
'#default_value' => array(
'Day' => format_date(time(), 'custom', 'j'),
'Month' => format_date(time(), 'custom', 'n'),
'Year' => format_date(time(), 'custom', 'Y'),
),
'#value' => array(
'day' => format_date(time(), 'custom', 'j'),
'month' => format_date(time(), 'custom', 'n'),
'year' => format_date(time(), 'custom', 'Y'),
),
'#process' => array('ds_ticket_expand_date'),
'#theme' => array('ds_ticket_date'),
'#printed' => true, // <--- Make it quit calling theme_date() needlessly.
);
?>And as you probably noticed, I also added a default value (today). With that whipped into shape, there's nothing left to do but add the CSS. I had to explicitly add some space at the bottom of the form element immediately above the date, because the LEGEND element in the date was too close to its predecessor for easy legibility, and adding margins or padding to the top of the fieldset did not help. (LEGEND element are notoriously difficult to style -- they just don't cooperate with a lot of ordinary style rules).
And all of this fuss because the W3C didn't see fit to give us a standard <input type="date" /> or <input type="time" /> back when they were last working on HTML, which would have been a better way to do it. That way the browser vendors could have worried about it once, and then we poor long-suffering web developers wouldn't have to. I wonder how many hours of time have been spent worrying about date/time inputs in forms? Probably a lot. And now we're getting fancy JavaScript datepicker widgets which are even more difficult to do in an accessible fashion.
I hope this helps someone, as I've just spent nearly 8 hours working out the code and documenting everything.
Comments
This is great, now what can we do to make it easier in D7?
Thanks for spending the day working through all of this. I'd really like to see some of this research get pulled out and put into specific issues for Drupal Core that can then be tagged and brought into the master list for accessibility improvements:
http://drupal.org/node/364629
We've been discussing a generic offscreen class in modules/system/system.css in this group. It would be good if there was a consistent way to hide for everyone & hide for screen readers.
Had some prior discussion about labels here:
http://drupal.org/node/368759
http://drupal.org/node/356359
What recommendations would you make to enhance the theme_date() function? You've got a series of good workarounds for D6, but it really should be much better by default.
Mike
OpenConcept | CLF 2.0 | Podcasting
--
OpenConcept | Twitter @mgifford | Drupal Security Guide
Hmm ...
Well, a generic off-screen class would be handy. There are some other things I've noticed, particularly in the admin pages.
1) Lack of labels for form elements in some lists of things. For example, if you go to Admin -> User Management -> Roles and edit the permissions for one given role, the labels for each check box are not marked up as labels, and the should be. The same problem occurs on the module uninstallation page. On individual lists like those, that's low-hanging fruit.
Obviously it's going to be more difficult on lists with multiple dimensions -- like if you go to admin/user/permissions, it lists all of the roles and all of the permissions in a giant table. Those don't have explicitly designated labels, in large part because of the structural limitation in HTML itself that I discussed above -- one element may have multiple labels, but one label can only apply to one element. Each of those check boxes logically has two labels: the role it applies to, and the permission it grants. There's no easy way to encode that relationship in HTML without adding a ton of hidden labels. It would help to use the HEADERS attribute on the TD elements containing each checkbox to associate each cell in the table with all the labels it can be applied to. Then at least the screen reader user could get the relevant information based on the table structure.
Along the same lines, it would be a good idea to review any tables in the admin pages to see if they've got SCOPE or HEADERS attributes on their TD and TH elements to make the structure of the table clearly readable by screen readers.
2) The sticky table headers code needs review for accessibility. Unless I'm mistaken, it adds a whole separate table to the document, duplicating the contents of the THEAD for the associated table. I suspect that's going to lead to a situation where the table headers get read twice, which is confusing. I haven't tried, it though. Does ARIA offer a way to designate a piece of added code as something the screen reader should ignore? If so, then that would be a good thing to do.
3) I haven't looked closely at this, but the draggable tables introduced in D6 look to me as though they depend exclusively on the mouse, meaning that screen reader users wouldn't be able to use them. Can they be controlled via keyboard somehow?
Back in fall of 2007 I thought about making an accessibility auditing module for evaluating the accessibility of user-submitted nodes. I figure, you can validate the accessibility of whatever theme you're doing once, and then that leaves the content. The university I've been working at for the last few years has an accessibility monitoring program called Watchfire WebXM. It's expensive, hogs network bandwidth -- the scans bring many campus systems to their knees once a month -- and generates reports that aren't terribly useful. Plus, it doesn't have any way to keep track of what it has already scanned and what it has not, so it re-scans the same files over and over and over again, month after month. I bet a module for Drupal could perform the same function a lot more efficiently, by helping people check first their theme, and then the individual pieces of content in isolation. And it could track which nodes had already passed inspection or been corrected, so it wouldn't need to redo the same node over and over.
Alas, I've never had time to put it into effect. So many cool things to do, so little time ...
Multiple Dimension Forms
Hi Guys!
Ad 1): In multiple dimension forms such as in Permissions table there is a work around that helps not only screen reader users but all people. Instead of label-tag, that is useles in those tables, it is possible to put a title-attribute on each checkbox with distinct info about both:
1. repeating the subject from the leftcost cell;
2) adding the role. Screen readers like JAWS use this work around very well.
Example:
<input type=checkbox" title="(admin | anonymous | ...): Administer users" />
The idea of an Drupal tool for checking accessibility of user entries is cool - but it will be a big deal of work :-)
Mario Batusic - Linz, Austria
Mario Batusic - Linz, Austria
Date Follow-up
Great exchange here.
First I wanted to point to to the Drupal core improvements - accessibility page. I've argued for a generic offscreen class there, but it really needs to have much more support. Unless we can get enough folks to say that a patch is important and going to help with accessibility, we're not ever going to see it in Drupal core. So, explain that it would help you on relevant issues.
It was a problem though with core that has been fixed. There is also a big push to get tables out of D7 all together. I just did a bit of a search and there were less than 6 links in core:
modules/block/block-admin-display-form.tpl.php: <td><?php print $data->region_select; ?></td>modules/block/block-admin-display-form.tpl.php: <td><?php print $data->weight_select; ?></td>
modules/block/block-admin-display-form.tpl.php: <td><?php print $data->configure_link; ?></td>
modules/block/block-admin-display-form.tpl.php: <td><?php print $data->delete_link; ?></td>
modules/system/system.admin.inc: $output .= '<tr class="' . $class . ' merge-down"><th>' . $requirement['title'] . '</th><td>' . $requirement['value'] . '</td></tr>';
modules/system/system.admin.inc: $output .= '<tr class="' . $class . '"><th>' . $requirement['title'] . '</th><td>' . $requirement['value'] . '</td></tr>';
Now, that's not perfect and there is no scope or header elements in them, but I think it's the right way to go.
2) We've got to stay focused on D7 as this is where the changes will be made. However, I did try this and got this for the sticky header:
<div id="node-1" class="node sticky"><h2><a href="/node/1" title="Long live the crocs">Long live the crocs</a></h2>
<div class="content clearfix">
<p>may the crocs live forever</p>
</div>
<div class="clearfix">
<div class="meta"></div>
</div>
</div>
No tables or THEAD's involved.
3) I don't really know as I haven't learned how to do this strangely. Have any tips?
Neat idea about the comprehensive accessibility module. Does seem like an interesting idea. I do think that htmLawed (X)HTML filter/purifier can go a long way in this direction. Although the Auto addition feature of htmLawed is a bit problematic as far as I am concerned.
--
OpenConcept | CLF 2.0 | Podcasting
--
OpenConcept | Twitter @mgifford | Drupal Security Guide
Content Navigation Rules (CNR)
Has anyone tracked this from Charles Chen's work (FireVox)?
CNR stands for Content Navigation Rule. CNRs are a part of AxsJAX. They allow web developers, web hackers, end users, and in short, anyone interested in accessibility, to define a set of simple rules for navigating a particular web site.
http://clcworld.blogspot.com/
Also - anyone on this list at DrupalCon D.C. meeting at Friday's BoF?
Quite Interessting Initiative
Thanks for sharing this. Followed it along to - http://code.google.com/p/google-axsjax/
Has anyone tried this? I haven't heard of CNR.
Mike
OpenConcept | CLF 2.0 | Podcasting
--
OpenConcept | Twitter @mgifford | Drupal Security Guide
CNR looks interesting, builds on WAI-ARIA
Hi Katherine,
Thanks for introducing this. I've looked at Firevox (useful!) and I'm trying to find opportunities to use WAI-ARIA (my email to W3C on ARIA DTD), but I hadn't come across CNR before. On a quick read I was a bit concerned, because it seems to do similar things, however actually it builds on it - great!
(My concerns,
And if I understand it from a quick read, developer X can help people to use their assistive technology with site Y, without having to get Y changed - that is, where they have no control over Y. Am I right?
(Oh, and it was a bit scary posting to the W3C, but no one's commented! :( ;) )
Must investigate more. Cheers,
Nick
--
Web Developer. Open University. Accessibility & standards.
--
Web Developer. Open University UK. Accessibility, HTML5 & standards.
http://twitter.com/nfreear
http://freear.org.uk
Get my book "Moodle 2 for Teaching 4-9 Year Olds,
http://facebook.com/moodle4.9.book
Ask Charles:
Ask Charles: http://www.daisy.org/stories/charles.shtml -> his website.
btw (!) Open University is a DAISY Member: http://www.daisy.org/about_us/mem_detail.shtml?id=286
progressive enhancement & dates
Just came back from an accessibility workshop. The speaker argued that in the the case of a date field (well and other fields too), it would be best to provide a text filed that one could just edit with YYYY-MM-DD HH:MM type content and then you could script a javascript application to make it much easier for most users to interact with. You'd want to also ensure that there is a lot of logic into the input date that it could be as smart as possible with the data.
Main goal though is that if the javascript application didn't work you'd still have a form that clearly explained how to fill in the information. Having many drop-downs to script is just awkward but a simple solution like this may resolve the issue.
Mike
OpenConcept | CLF 2.0 | Podcasting
--
OpenConcept | Twitter @mgifford | Drupal Security Guide
Hmm ...
I hate being a nay-sayer, but I remain highly skeptical of this approach.
When I was working on the date pickers for my current project, I looked at a JavaScript-powered date picker widget exactly like the one your speaker described. It's just a text input with a little calendar icon next to it that pops up a nice little calendar. Here are some working demos of the script.
I really, really wish I could use that. It's straightforward, unobtrusive, and easy to use. But as soon as I fired up some screen readers to test it, it was an abject failure. The javascript widget (whenever triggered) caused the computer to speak unfathomable gibberish for five minutes. And when it wasn't triggered, the date field was just a text field labeled "date" with no instructions on how to figure out the format of the date. That could be remedied with a label, as you suggest, but it'd be a pretty long and complex label. I strongly suspect it would be hard to use sans JS even with a label.
If we're looking at just entering dates in a text field, I'd prefer a server-side solution. Take a look at PHP's strtotime() function, which takes a human-written string in a huge variety of formats, and tries to make an intelligent guess as to what that means. It'll work with everything from fully qualified YYYY-MM-DD HH:MM formatted content to things as vague as "next Thursday". In order to provide some pre-submit sanity checking, we could use either an AJAX script to ask the server if it understands the date as written, or else implement a JS equivalent of strtotime().
Really, though, in the long run the only good solution to this problem is for the browser vendors to deal with it. The HTML5 INPUT element spec adds types for date, time, datetime, week, and a bunch of others. The sooner those get implemented and out in the wild, the better. I remain hopeful of being able to use before I retire. Which won't happen for another 30-40 years; surely given several decades to work on it the browser makers ought to be able to get a decent date input figured out. Right? Right???
Now that we're working on D8
We should look at this again with respect to HTML5.
--
OpenConcept | Twitter @mgifford | Drupal Security Guide