CodeDigest.Com Logo
Featured:

Creating Accessible Input Forms in Asp.Net MVC - Section 508 Compliance and ADA Compliance

Tagged as: Asp.Net Asp.Net MVC Accessibility Posted By

Making the web page accessible to everyone including disabled people is becoming one of the primary requirements for every web applications we develop. Many countries has made it mandatory and there are compliance and legal framework that has to be considered for this. Making web accessible to disabled people requires our web application should be accessible to various assistive technologies like screen readers, etc.

To know more about general Web Content Accessibility Guidelines (WCAG), accessibility criteria’s and issues, I would suggest you to read the below quick start article.

What is Web Accessibility Guidelines & Section 508 Compliance? Build Screen Reader Friendly WebSites

Moving forward, let’s see how to build an accessible input forms in Asp.Net MVC project. Except the Asp.Net syntax, the concepts and techniques discussed in these article are same whatever technology stack (JAVA, PHP, ROR, etc.) you use. I chose Asp.Net MVC since I am basically an Asp.Net developer. I will use the NVDA screen reader and its speech viewer tool to demonstrate how the input forms are read to users wherever required in this article.

There are various ways to make a form accessible, I will discuss one of the approach here to make the input controls are properly read out to disabled users. The accessibility solution discussed here comes under the guidelines 2.4.6 Headings and Labels, 3.3.2 Labels or Instructions and 3.3.5 Help.

Making Input Forms Accessible

In general, whenever we develop an input form, the form should have proper heading for sections, labels for controls, it should include proper help text for specific input controls (password complexity hint) and it should also indicate in some way about the mandatory fields so that it is perfectly accessible. Let’s see how to make this happen in an Asp.Net MVC views.

Label with Input Control

To read out the label associated with an input control, it is required that the input control and the label is associated with label’s “for” attribute. The default code generated by most code generators you use (Visual Studio Scaffolding for Asp.Net MVC) are mostly likely that they are already complaint. The generated HTML for FirstName input field will look like below.

<div class="form-group">
    <label class="control-label col-md-2" for="FirstName">First Name</label>
    <div class="col-md-10">
    <input class="form-control text-box single-line" data-val="true" data-val-maxlength="The field First Name must be a string or array type with a maximum length of '50'." data-val-maxlength-max="50" data-val-required="The First Name field is required." id="FirstName" name="FirstName" value="" type="text">
    </div>
</div>

 

In the above code, you could see the label’s for attribute is set with the input control’s id it is associated with. This will make sure the field is read out properly to the screen reader users. Refer the below screenshot which shows NVDA speech viewer log.

 

Note NVDA is one of the most commonly used and free screen reader tool. It has a Speech Viewer tool which prints the readers output as text. To enable this speech viewer, after installation, start the NVDA software, right click the NVDA reader icon in taskbar and click Tools > Speech Viewer.

The Razor code for the MVC view is below,

<div class="form-group">
    @Html.LabelFor(model => model.FirstName, htmlAttributes: new { @class = "control-label col-md-2" })
    <div class="col-md-10">
        @Html.EditorFor(model => model.FirstName, new { htmlAttributes = new { @class = "form-control" } })
    </div>
</div>

 

Input Control without Label (Only Placeholder)

In this case, though the screen reader recognizes the placeholder text and reads out in most of the browsers it is necessary that we include an ARIA attribute called aria-label for the textbox input control. ARIA stands for Accessible Rich Internet Applications. There are some mobile readers that will ignore these placeholders, so this attribute should be used to hint the screen reader that the input field’s label text is included in this attribute. The generated HTML is,

<div class="form-group">      
    <div class="col-md-offset-2 col-md-10">
    <input aria-label="Postal Code" class="form-control text-box single-line" data-val="true" data-val-maxlength="The field Postal Code must be a string or array type with a maximum length of '10'." data-val-maxlength-max="10" data-val-required="The Postal Code field is required." id="PostalCode" name="PostalCode" placeholder="Postal Code" value="" type="text">
    </div>
</div>

 

The razor code for MVC view is,

<div class="form-group">
    <div class="col-md-offset-2 col-md-10">
        @Html.EditorFor(model => model.PostalCode, new { htmlAttributes = new { @class = "form-control", aria_label= "Postal Code", placeholder= "Postal Code" } })
    </div>
</div>

 

Please note the HTML helper will automatically converts the aria_label to aria-label attribute when generating the HTML.

 

 

Reading Mandatory for Input Controls

When the input control label is read out by the screen reader it is a good practise to mention if that field is mandatory or required. This can be done by including “*” in the label text and having a generic description at the start of the form mentioning “Field marked with * are mandatory”. Or another best way is to include aria-required=”true” in those fields that are mandatory. This will read the field as mandatory. The HTML for this is below.

<div class="form-group">
    <span class="control-label col-md-2" id="addess1-label">Address Line1</span>
    <div class="col-md-10">
        <input aria-labelledby="addess1-label" aria-required="true" id="Address1" name="Address1" value="" type="text">
    </div>
</div>

The screen reader will now read out saying “required” for this field as below.

 

The Razor code for MVC view is below.

<div class="form-group">
    @Html.LabelFor(model => model.Address1, htmlAttributes: new { @class = "control-label col-md-2"})
    <div class="col-md-10">
        @Html.EditorFor(model => model.Address1, new { htmlAttributes = new { @class = "form-control", aria_required = "true" } })
    </div>
</div>
 

As mentioned in previous section, the aria_required will be automatically converted to aria-required by the HTML helper.

Note - There are more about making the form errors and validation accessible, let’s see that in a different article. Here, in this article, we will try to understand how to make the form controls accessible for the screen reader.

Input Controls with Hint Text

Sometimes, we will have input controls with hints associated with it. For example, password complexity hint or allowed characters hint or a format. For example, the below Date Of Birth field has hint text about the format it allows.

To make the screen reader recognize and read the hint text for an input control we should use aria-describedby attribute. The attribute takes id of the container that has the hint text and the screen reader will read out the hint when the control is in focus. Refer the NVDA speech viewer screen shot below.

The generated HTML output is,

<div class="form-group">
    <label class="control-label col-md-2" for="DOB">Date of Birth</label>
    <div class="col-md-10">
        <input aria-describedby="dob-format" class="form-control text-box single-line" data-val="true" data-val-date="The field Date of Birth must be a date." id="DOB" name="DOB" value="" type="datetime">        
        <span id="dob-format"><strong>Format:</strong> dd/mm/yyyy</span>
    </div>
</div>
 

The MVC razor view code is below.

<div class="form-group">
    @Html.LabelFor(model => model.DOB, htmlAttributes: new { @class = "control-label col-md-2" })
    <div class="col-md-10">
        @Html.EditorFor(model => model.DOB, new { htmlAttributes = new { @class = "form-control", aria_describedby = "dob-format" } })
        <span id="dob-format"><strong>Format:</strong> dd/mm/yyyy</span>
    </div>
</div>

 

Forms with Section Heading

There are forms where we will have multiple section with similar input controls grouped together. For example, the below form contains 2 section with “Personal Details and Communication Details” as section heading.

In this cases, the screen reader should properly read out the heading before announcing the individual input controls. Look at the below NVDA reader Speech Viewer log.

Though we can achieve this in multiple ways, we can best address these scenarios by using <fieldset> and including the section heading in <legend>. The screen reader automatically reads the legend as heading and says “grouping” before reading out the input controls under it as seen in above screen shot.

The generated HTML is,

<fieldset>
    <legend>Personal Details</legend>
    <hr>
    <div class="form-group">
        <label class="control-label col-md-2" for="FirstName">First Name</label>
        <div class="col-md-10">
            <input class="form-control text-box single-line" data-val="true" data-val-maxlength="The field First Name must be a string or array type with a maximum length of '50'." data-val-maxlength-max="50" data-val-required="The First Name field is required." id="FirstName" name="FirstName" value="" type="text">            
        </div>
    </div>

    <!-- Truncated for brevity -->    
</fieldset>

 

Note – There might be style changes due to the inclusion of fieldset which needs to be addressed.

Forms with Section Heading and Sub Headings

As seen in previous section, each sections may have sub-headings. For example, the below “Communication Details” section has “Postal Address” and “Contact Online” sub heading associated with it.

As you might have guessed, we can nest <Fieldset> and include the sub heading in a legend to make it read. Since it is already discussed, let’s use another technique to read the sub heading with aria-labelledby attribute. This attribute is similar to aria-label attribute but it takes the id of the container that has the label or heading. It also takes multiple ids and read out the headings in the order it is specified.

The generated HTML is,

<fieldset>
    <legend>
        Communication Details
    </legend>
    <hr>
    <div id="postal-contact"><strong>Postal Address</strong></div>
    <div class="form-group">
        <label class="control-label col-md-2" for="Address1" id="addess1-label">Address Line1</label>
        <div class="col-md-10">
            <input aria-labelledby="postal-contact addess1-label" aria-required="true" class="form-control text-box single-line" data-val="true" data-val-maxlength="The field Address Line1 must be a string or array type with a maximum length of '50'." data-val-maxlength-max="50" data-val-required="The Address Line1 field is required." id="Address1" name="Address1" value="" type="text">
        </div>
    </div>

    <!-- Removed for brevity -->

    <div id="contact-online"><strong>Contact Online</strong></div>
    <div class="form-group">
        <label class="control-label col-md-2" for="Email" id="email-label">Email</label>
        <div class="col-md-10">
            <input aria-labelledby="contact-online email-label" aria-required="true" class="form-control text-box single-line" data-val="true" data-val-maxlength="The field Email must be a string or array type with a maximum length of '100'." data-val-maxlength-max="100" data-val-regex="Check email address format!" data-val-regex-pattern="[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,4}" data-val-required="The Email field is required." id="Email" name="Email" value="" type="text">
            
        </div>
    </div>

    <!-- Removed for brevity -->

</fieldset>

 

If you notice the code above, I have included id for the label and in aria-labelledby I have given the label’s id next to the sub heading’s id. This is because, when we include aria-labelledby to a control that already has label associated then the screen reader takes priority to aria-labelledby and it will ignore the label. This is why I have set the label’s id as second argument (aria-labelledby="postal-contact addess1-label").

Screen reader output below.

The Razor code in MVC view is below.

<fieldset>
<legend>
    Communication Details
</legend>
<hr />
<div id="postal-contact"><strong>Postal Address</strong></div>
<div class="form-group">
    @Html.LabelFor(model => model.Address1, htmlAttributes: new { @class = "control-label col-md-2", id = "addess1-label" })
    <div class="col-md-10">
        @Html.EditorFor(model => model.Address1, new { htmlAttributes = new { @class = "form-control", aria_required = "true", aria_labelledby= "postal-contact addess1-label" } })
    </div>
</div>

 

<!-- Removed for brevity -->

<div id="contact-online"><strong>Contact Online</strong></div>
<div class="form-group">
    @Html.LabelFor(model => model.Email, htmlAttributes: new { @class = "control-label col-md-2", id="email-label" })
    <div class="col-md-10">
        @Html.EditorFor(model => model.Email, new { htmlAttributes = new { @class = "form-control", aria_required = "true", aria_labelledby = "contact-online email-label" } })
    </div>
</div>

 

<!-- Removed for brevity -->
</fieldset>

 

Use of aria-labelledBy attribute

Though we have used aria-labelledby attribute to deal with sub heading scenarios discussed above, it is designed for using it as a label for an input controls. For example, in some existing forms the input controls label might be included in a <span> or <div> instead of label. In these cases, we can use aria-labelledby to make the screen readers recognize the label associated with the input control. Refer the below HTML for its usage.

<div class="form-group">
    <span class="control-label col-md-2" id="addess1-label">Address Line1</span>
    <div class="col-md-10">
        <input aria-labelledby="addess1-label" aria-required="true" id="Address1" name="Address1" value="" type="text">
    </div>
</div>

 

 

That’s it! we have seen almost all possible scenario to make the input forms accessible.

The form and final screen reader output for the whole form is below.



Feedback

Comments