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');
}
});
})
Each time a visitor traverses to a page, the menu item is easy to tell where they are as shown below.
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).
Then for each page which has focusable inputs add id="main-content"
Example
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>
Steps to remedy this for screen readers.
- Add a description using aria-description to each radio button
- Add 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 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>
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>
}
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);
}
}
Fire up the page, open developer tools and inspect. Try checking another radio button.
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
Source code
Clone the following GitHub repository.
Part 2
Will have more accessibility tips and techniques.