DEV Community

Cover image for Tips on making a web site accessible part 1
Karen Payne
Karen Payne

Posted on • Edited on

Tips on making a web site accessible part 1

Where in the heck am I?

There is a chance a visitor to a site may land on a page that does not make sense, is out of context.

One idea where there is a navigation menu is to highlight the current menu item for the current page.

For ASP.NET Core and Razor Pages, add the following code to site.js.

document.addEventListener('DOMContentLoaded', () => {

    document.querySelectorAll('.nav-link').forEach(link => {

        link.classList.remove('text-dark');
        link.classList.remove('bg-primary');

        if (link.getAttribute('href').toLowerCase() === location.pathname.toLowerCase()) {
            link.classList.add('text-white');
            link.classList.add('bg-primary');
        } else {
            link.classList.add('text-dark');
        }
    });

})
Enter fullscreen mode Exit fullscreen mode

Each time a visitor traverses to a page, the menu item is easy to tell where they are as shown below.

Highlighted menu item

Skip links

A skip link is a technique for facilitating similarly efficient access for users with certain disabilities. A "skip navigation" link is implemented by placing a named anchor at the point on the page where the main content begins (e.g., ).

Many commercial web sites provide skip links, go to Amazon and press TAB which presents a window, press ENTER to go to main content skipping navigation.

For ASP.NET Core and Razor Pages, open _Layout.cshtml and and the following (it's included in the source code).

Code for _Layout file

Then for each page which has focusable inputs add id="main-content"

Example

form with id set to main-content

Radio buttons

Radio buttons are well known inputs, only one radio button in a given group can be selected at the same time. In the following code, a ambulatory visitor has no issues to which radio button is checked but for visually impaired using a screen reader has no indicators which radio button is checked.

Render the following code on a page, open a screen reader like NVDA and listen after checking one of the radio buttons.

<form>
    <input name="colour" value="blue" id="choice1" type="radio">
    <label for="choice1"> Blue</label>

    <input name="colour" value="green" id="choice2" type="radio">
    <label for="choice2"> Green</label>

    <input name="colour" value="green" id="choice3" type="radio">
    <label for="choice3"> Red</label>

</form>
Enter fullscreen mode Exit fullscreen mode

Steps to remedy this for screen readers.

The aria-checked attribute indicates the current "checked" state of checkboxes, radio buttons but needs the developer to write code to set the current "check" state.

Step 1, add the following library jQuery WAI-ARIA to your project.

Step 2, add elements to the page.

<div class="container">
    <div id="test" aria-flowto="false"></div>
    <form method="post" name="form1" id="main-content">

        <input type="hidden" asp-for="BlueRadio" id="BlueCheckBox"/>
        <input type="hidden" asp-for="RedRadio" id="RedCheckBox"/>
        <input type="hidden" asp-for="GreenRadio" id="GreenCheckBox"/>

        <fieldset class="border border-warning p-3 bg-light" style="width: 20em;">

            <legend class="float-none w-auto fs-6 text-danger">Favorite color</legend>

            <div class="form-check">
                <input aria-checked="false"  
                       aria-description="Blue"
                       class="form-check-input" 
                       type="radio" 
                       name="ColorRadioGroup" 
                       id="flexRadioDefault1">

                <label class="form-check-label" for="flexRadioDefault1">
                    Blue
                </label>
            </div>

            <div class="form-check">
                <input aria-checked="false" 
                       aria-description="Red"
                       class="form-check-input" 
                       type="radio" 
                       name="ColorRadioGroup" 
                       id="flexRadioDefault2">
                <label class="form-check-label" for="flexRadioDefault2">
                    Red
                </label>
            </div>

            <div class="form-check">
                <input aria-checked="false" 
                       aria-description="Green"
                       class="form-check-input" 
                       type="radio" name="ColorRadioGroup" 
                       id="flexRadioDefault3">
                <label class="form-check-label" for="flexRadioDefault3">
                    Green
                </label>
            </div>

        </fieldset>

        <div class="row">
            <button id="btn-submit" class="w-25 btn btn-primary m-2" type="submit">Submit</button>
        </div>

    </form>
</div>
Enter fullscreen mode Exit fullscreen mode

Add JavaScript, here it's in the page but can also be in an external file.

  • Creates an array of radio buttons
  • For each radio button assign an onclick event
  • In the onclick event, set aria-checked to false followed by iterating the array in the first bullet, find a match for the current radio buttn and set aria-checked to true.

The form submit event assigns values to hidden elements which are using in the OnPost event.

@section Scripts
{
    <script src="lib/ariaLib/jquery.aria.min.js"></script>

    <script>

        const radioGroups = document.querySelectorAll('input[type=radio]');

        /*
         * Assign onClick for each radio button, see also Form1 where
         * we target a specific group of radio buttons
         */
        for (var index = 0, max = radioGroups.length; index < max; index++) {
            radioGroups[index].onclick = function() {
                handleClick(this.id);
            }
        }


        /*
         * Responsible for setting aria-checked for each radio button
         */
        function handleClick(identifier) {

            // set all to false
            $('input:radio[name=ColorRadioGroup]').each(function() {
                $(this).ariaState({ "checked": false });
            });

            // set current to true
            for (let index = 0, groups = radioGroups.length; index < groups; index++) {
                if (radioGroups[index].id === identifier) {
                    document.getElementById(identifier).setAttribute('aria-checked', 'true');
                    document.getElementById(identifier).setAttribute('checked', 'true');
                }
            }

        }

        // Assign checked aria checked to page properties $("#BlueCheckBox").ariaState("checked");
        $('form').submit(function(e) {
            document.getElementById("BlueCheckBox").value = document.getElementById("flexRadioDefault1").ariaChecked;
            document.getElementById("RedCheckBox").value = document.getElementById("flexRadioDefault2").checked;
            document.getElementById("GreenCheckBox").value = document.getElementById("flexRadioDefault3").checked;
        });

    </script>
}
Enter fullscreen mode Exit fullscreen mode

Backend code to log checked states

public class BootstrapPageModel : PageModel
{
    [BindProperty]
    public bool BlueRadio { get; set; }

    [BindProperty]
    public bool RedRadio { get; set; }

    [BindProperty]
    public bool GreenRadio { get; set; }

    public void OnGet()
    {
    }

    public void OnPost()
    {
        Log.Information("Blue {P1}", BlueRadio);
        Log.Information("Red {P1}", RedRadio);
        Log.Information("Green {P1}", GreenRadio);
    }
}
Enter fullscreen mode Exit fullscreen mode

Fire up the page, open developer tools and inspect. Try checking another radio button.

Page with developer tools open

Next, fire up the page with a screen reader for the ultimate test.

Note
In supplied source code there are variations on wrong and right ways to accommodate visually impaired.

Data

On one page, CategoriesPage.cshtml, SQL-Server and EF Core are used. Before running, create and populate the database with scripts.sql.

Root\Data\Scripts.sql

shows where the database script is located

Source code

Clone the following GitHub repository.

Part 2

Will have more accessibility tips and techniques.

Top comments (0)