I have been doing a bit of accessibility work for a clients public facing website recently. One of the key areas was ensuring the feedback form was accessible to users with screen readers, which meant ensuring inputs have appropriately associated labels (amongst other things).

For most standard inputs this isn't a problem - text boxes, radio/check box lists work well enough with the ASP.NET Label controls. However, they were also using the SharePoint AssociatedControlID attribute won't have the desired effect, since at render time the "control" will just be a div. Consequently, when a vision impaired user focuses on the date input field, they don't get any hints read out. Furthermore, clicking a label will normally move focus to the associated text box input; but this functionality is also lost.

As part of my attempts to validate the DateTimeControl, I came across ControlToValidate property to {ControlId}${ControlId}Date and it will validate the actual date part of the datetime. Neat!

So I tried this with the AssociatedControlID property of the Label control:

<asp:Label runat="server" ID="FaultDateLabel" AssociatedControlID="FaultDate$FaultDateDate" Text="Fault Date" />

It worked beautifully!

  1. When tabbing to the date portion of the DateTimeControl while using a screen reader, the software correctly read out "Fault Date"
  2. When clicking the "Fault Date" label, focus was given to the date portion of the DateTimeControl.

Awesome :)

But one thing annoys me about these "static" Label controls… why do they need to be a server control? I'm not accessing it via code, nor referencing it in any other why, so why add another control to the control tree (and probably more to the ViewState)? I tried the following, and was pleasantly surprised:

<label for="<%= DateFrom.ClientID %>__DateFromDate">Fault Date</label>

It worked just as well. A couple of things to note:

  1. You need to use ClientID, not ControlID, since we need to output the long horrible generated ID (when using auto IDs)
  2. The generated ID delimits each nested control with a double underscore, not a dollar sign like when referencing the nested control server side

I wasn't sure whether this is best practice or if it has any performance implications, but after a quick read of Improving ASP.NET Performance, it seems this isn't so bad (and actually recommended for heavy pages or controls) as it writes directly to the response stream.