Tips on making a web site accessible part 1
Tags: css, javascript, csharp, a11y
Published: 2023-04-23 01:54:58

## 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.

```javascript
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');
        }
    });

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


![Highlighted menu item](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q48clqvfan6sfdpd8knw.png)

## 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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nfezmo5gv3fh9trt3yjh.png)

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

Example

![form with id set to main-content](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gqwf70hccm62f5kuj5d1.png)

## 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](https://www.nvaccess.org/) and listen after checking one of the radio buttons.

```html
<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>
```

Steps to remedy this for screen readers.

- Add a description using [aria-description](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-description
) to each radio button
- Add [aria-checked](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-checked) to each radio button

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](https://github.com/Skateside/jquery-aria) to your project.

Step 2, add elements to the page.

```html
<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>
```

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.

```javascript
@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>
}
```

Backend code to log checked states

```csharp
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);
    }
}
```
Fire up the page, open developer tools and inspect. Try checking another radio button.


![Page with developer tools open](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oq5p045shp566uy3p4oc.png)

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cttauu768ddp95vcg2h5.png)

## Source code

Clone the following [GitHub repository](https://github.com/karenpayneoregon/web-accessibility-1).

## Part 2

Will have more accessibility tips and techniques.