Developer Area/Accessibility Checklist
From Mahara Wiki
< Developer Area
See also Accessibility for an overview of Mahara's stance on accessibility.
Checklist for developers: Things to think about when designing for accessibility
Note: Any explanatory text (text which should be hidden from sighted users but available to screen readers) should be in an element with class sr-only (for Mahara 15.10 through to 22.04) or visually-hidden (for Mahara 22.10+).
Testing
- Always test with a screen reader, preferably more than one (Orca in Linux, JAWS or NVDA in Windows, VoiceOver in OS X, etc.) Often this will give different results than testing for keyboard accessibility without a screen reader
- Use HTML validators (such as WAVE Accessibility Checker or the W3C Validation Service) to make sure there are no serious errors
http://accessibility.psu.edu/protocol has a good overview of various ways you can test.
General
- All images need alt text, unless it would mean duplicating the text beside them (in which case have alt=""). If the image is a link or button, the text should describe what it links to. Otherwise, it should just say what the image is/shows. Note that this covers both <img> and <input type="image"> elements
Example: {* describing what an image shows *} <img src="{theme_url images/success_small.png}" alt="{str tag=completed section=artefact.plans}"> {* identifying where a link goes *}
<a href="/account/activity/index.php"><img src="{theme_url images/message.png}" alt="{str tag=inbox}"></a>
{* showing what a button does *} <input type="image" src="{theme_url images/btn_configure.png}" alt="{str tag=configure}">
A helpful guide for alt text can be found here: 4syllables - Text alternatives – a decision tree
- Use descriptive text in links and buttons - no "Click here" links. You should be able to work out what the link does without looking at the surrounding text
- Use buttons and links consistently.
- Use a link if you're navigating to a predefined page or section (navigation, tabs, etc.)
- Use a button if you're changing information or state (submitting a form, editing or deleting content, searching, etc.)
- Never use a positive tabindex, but do use tabindex="0" or tabindex="-1" for elements which should be focusable but aren't by default
- tabindex="-1" means it can take focus (via Javascript) but cannot be reached by sequential focus navigation (i.e. tabbing)
- tabindex="0" means it can take focus and can be reached by tabbing
- Elements that are by default focusable and can be reached by tabbing are mainly links and form elements. See http://www.w3.org/TR/html5/editing.html#sequential-focus-navigation-and-the-tabindex-attribute
- Make sure everything that can be done with a mouse can also be done with a keyboard. Common pitfalls include
- Drag and drop (an accessible alternative should be provided)
- Elements that are clickable but are actually divs or spans (either they should be changed to be either button or a tags, or tabindex="0" and the "keydown" event should be used)
Example: (OK) <span class="button" tabindex="0">Create group jQuery('.button').on('click keydown', function(event) { // This will fire when the button is clicked or when the user presses Space or Enter on it if ((event.type == 'click' && event.buttons > 0) || event.keyCode == 32 || event.keyCode == 13) { // Do something } }); (Better) <button type="button" class="button">Create group</button> jQuery('.button').click(function(event) { // For buttons, the 'click' event will catch Space/Enter as well // Do something });
- Generally speaking, use the smallest number of elements necessary to achieve your purpose, and use semantic ones where appropriate
Forms
- All form elements need labels, without exception. If a label wouldn't look good then make it hidden (if you're using pieforms to do this just set 'hiddenlabel' to true)
Example: {* in a template *} <input id="username" type="text" name="username" /> <label for="username" class="sr-only">{str tag=username}</label> // Using pieforms 'username' => array( 'type' => 'text', 'title' => get_string('username'), 'hiddenlabel' => true, // ... )
- Include a description of the format you expect when creating format-specific text boxes such as date entries or colour pickers. Something like "Use the format YYYY/MM/DD" is enough. It's also nice to accept multiple formats even if you only describe one, accepting either YYYY/MM/DD or YY/MM/DD in a date entry for example
JavaScript and AJAX
- If you load content with AJAX or hide/show content, move focus to the start (first element or first focusable element) of what you loaded
Example: jQuery('.expandable-head a.toggle').click(function() { var body = jQuery(this).next('.expandable-body') body.toggle(); if (body.is(':visible')) { // Set focus body.find('a').first().focus(); } });
- Small dialogs (such as help boxes) should be inserted into the tab order after the element which activates them. Large ones should open outside the main content (ie. at the end of the <body>), set focus to their close button and set the aria-hidden attribute on the rest of the page (usually #container)
Example: jQuery('#dialog').appendTo('body').show(); jQuery('#dialog .closebutton').focus(); jQuery('#container').attr('aria-hidden', true);
- Widgets like tabs, accordions, etc. need hidden text to show their state. Basically, whenever you programmatically change the state of a widget (active, inactive, disabled, etc.) you should use hidden text to show which state the widget is in
Example: <li class="current-tab">First tab <span class="sr-only">(tab selected)</span></li> <li>Second tab <span class="sr-only">(tab)</span></li>
When the second tab is clicked, its accessible text should change to "(tab selected)" and that of the first tab should change to "(tab)"