Often at conferences or client sites while doing demonstrations of SharePoint forms I often get asked if SharePoint supports section 508 Compliancy. This is a big question and the answer is really no, however it does support XHMTL 1.0 Strict, WCAG 2.0 Level AA and WAI:ARIA, this does not include Central Administration though. However for section 508 it does not completely pass. There is not a lot of documentation out there about making SharePoint comply, well at least for the 2010 version. In this post I will look at creating a SharePoint form within a web part and the issues that are presented when trying to achieve basic section 508.
So firstly let's take a look at some base HTML markup that SharePoint outputs within a list view web part.
The html markup is a little bit messy to read but the first think you notice that is missing from well-formed section 508 compliant mark-up is:
The issue with this is that even though the markup is correct and valid for users with assistive technology it would not work as expected. The key effect of this is that when a user clicks the label even with a regular mouse with this code alongside an input element it automatically moves the focus to that field. So how come they do not appear in SharePoint?
I am not 100% sure why they do not but one of the reasons is that SharePoint has to ensure that each field is uniquely named to not cause conflicts. To achieve this, the ID of the field becomes a combination of the Client ID (generally parent container ID), actual field name and then some type text appended to the end that is not captured until the page begins to render.
This becomes a problem for us as developers to ensure that everything is named correctly for the rendering of the markup to be 508 compliant. The worse news is that other fields native SharePoint are very complicated and the markup is very very messy. The managed metadata field looks like this:
As you can see there are multiple elements with the similar names that make this control very complicated to work with. The rich text editor fields, as well as any of the picker controls are all built this way which makes coding them very complicated. However there is light at the end of the tunnel. If we decide to write a web part or in my case a user control which references SharePoint fields we are able to use client script to retrieve the correct ID, however this runs after the page is loaded and does not really have the affect we are looking for. Eric Shupps (SharePoint Cowboy) has a great post about this here.
For my demos however I did not want any code to run after the page loads I wanted it to render exactly as I wanted before the page is displayed to the end user. For my user control I decided to render the following code:
This was going to output my label and then my SharePoint field ready for the user to complete. Firstly I looked into using the "AssociatedControlID" property of the label control to tie the two together, details can be found here. This worked to an extent as I was able to pass the control ID so for example using my demo code.
This then outputted my html markup as this:
So it came almost there, but SharePoint jumped in again and appended that pesky type and control structure value again. After some testing and many many failed attempts I decided to inherit from the SharePoint FormField class and override the OnPreRender method and modify the name. I tried using OnPreRender, OnInit and OnLoad to no avail. I then decided to use the "RenderControl" method and use a simple regex replace method to modify the HTML outputted by SharePoint. Now this worked very well. I ended up with the following:
So after a cried for a while, banged my head against the wall I thought differently and tried a new approach. I decided to not inherit from the SharePoint control but to create a custom label control, just a straight inherit from the asp label control. I added my custom regex replace code to replace the "for" tag with a custom ID that I was passing for the field, modified my user control and ran it. No look still failed, as again the SharePoint pipeline adds the extra type at some magical point in the rendering!!
I thought I was losing the will to live and that it was not possible without creating completely custom controls to do everything which I did not want to. Funny how something as a question at a conference becomes a full scale investigation!!
In my darkest hour I thought well let me just screen scrape the HTML from multiple lists and libraries and see what SharePoint appending. To my surprise it was the same logic for each of the types of fields that SharePoint supports. For example when using a SharePoint FormField set as a single line of text it outputs "_ctl00_ctl00_TextField" at the end of the "Client ID", "Field Name" combination. I found that all types are appended that way and some need you to look at the base type and then the a few other properties to determine the type to append. So after all that I was able to use something like this:
This then rendered my form as the following:
And yes the "Truth does set you Free!!"
I finally had it working for all the field types that my SharePoint server supported, obviously it does not scale potentially for other custom field types that get created, but I was happy now I can create section 508 compliant fields with the correct label for code. This has been one of those mammoth investigations, trying one thing, failing and trying again. All in all it has been a great learning curve to really see how the SharePoint controls have been built and really how complicated it can really be to do something that you would think would be simple.
If there are any better cleaner ways of doing this that do not involve tons of coding such as control adapters or custom controls to match each SharePoint Control I would love to hear from you!! :-)