There are five main rules (and a few exceptions) to using ARIA:
Rule #1: Use a native HTML element or attribute
If you can use a native HTML element or attribute with the SEMANTICS and BEHAVIOR you need already built in, then do so. Instead of re-purposing an non-semantic element by adding ARIA role, states, or properties to make it accessible.
REAL LIFE SCENARIO: A real dog is better than a stuffed (fake) dog any day of the week.
Instead of doing this:
<div role=”button”>Click Me</div>
Will render as:
Click Me
Do this instead:
<button>Click Me</button>
Will render as:
The browser itself does not know that the <div> with a role of “button” is a button, only its accessibility API does.
EXCEPTIONS:
There are times when this may not be possible:
If the native element or attribute does not support accessibility
If the native element cannot be styled because of design constraints
Rule #2: Do not change the native element semantics
Unless you really have to, do not change native element semantics.
EXAMPLE: Instead of doing this: [CHANGE WITH ANOTHER EXAMPLE LATER]
<h2 role="tab">heading tab</h2>
Do this:
<div role="tab"><h2>heading tab</h2></div>
NOTE: By KEEPING the current native semantic element (e.g., h2) and WRAPPING it with a generic non-semantic element (e.g., div) with the role you need (e.g., tab) will cause the top level non-semantic element to have the role instead.
EXCEPTIONS:
There are times when this may not be possible:
If a non-interactive element is used as the basis for an interactive element, developers have to add the semantics using ARIA and the appropriate interaction behavior using scripting. In the case of a button, it is much better and easier to just use a native HTML button element.
It is OK to use native HTML elements, that have similar semantics to ARIA roles used, for fallback. For example, using HTML list elements for the skeleton of an ARIA-enabled, scripted tree widget.
IMPORTANT NOTE:
It is important to remember that an ARIA role will OVERRIDE existing NATIVEHTML SEMANTICS (meaning) ROLE but will NOTCHANGE its DEFAULTBEHAVIORS, STATES, or PROPERTIES to make it look or act differently. Hence, ARIA will affect what is reported to a screen reader or other assistive technology.
NOTE: Not exactly want you would want to do, but this illustrates this concept easily.
REAL LIFE SCENARIO: Just because I call you a lion, tiger, or bear does not make you a lion, tiger, or bear. However, you could “add on” some of these animal behaviors to mimic them (e.g., you could roar like a lion). For you city folks, just because a cat has her kittens in an old oven in your backyard, does make them biscuits.
TIP: Follow the principle of the duck test – "If it looks like a duck, swims like a duck, and quacks like a duck, then it probably is a duck" – suggests that something can be identified by its habitual characteristics. So, if it looks like a button, acts like a button, then it probably is a button.
EXAMPLE:
If you want to make the <h1> element act like a button:
Don’t do this:
<h1 role=”button”>Text</h1>
Do this instead: Wrap the text in a span element with a role of button inside of the <h1> element
<h1><span role=”button”>Heading</span></h1>
Or better yet, do this: Wrap the text in a semantic button element inside of the <h1> element
<h1><button>Heading</button></h1>
NOTE: Again, not exactly want you would want to do often but this illustrates this concept easily.
Rule #3: ARIA controls must be keyboard accessible.
All interactive ARIA controls must be keyboard accessible. If you create an interactive control for a widget that can be:
click or tap
drag or drop
slide or scroll
A user must be able to navigate to the control and perform an equivalent action with the keyboard. These controls must be programmed via script (e.g., JavaScript) to respond to standard keyboard or keyboard combinations.
EXAMPLE:
If you assign a role = “button” to an element, that element must be able to:
Receive focus when tabto like a button
Able to activate the action associated with the element like a button
Use both the ENTER / RETURN or SPACE key to commit the action like a button
Rule #4: Do not use role=”presentation” OR
aria-hidden=”true” on focusable element.
Using either role=”presentation” OR aria-hidden=”true” on a focusable element will result in some users focusing on nothing.
So, if you do this:
<button role=”presentation”>Hello World</button> OR <button aria-hidden="true">Hello World</button>
It will become this on the accessibility tree:
<>Hello World</>
Elements that don’t require children (e.g., heading element - <h1>) will not have the semantics of their children elements removed. However, elements that require children (e.g., bullet list <ol> and <li>) will have their semantics removed.
REAL LIFE SCENARIO: Adoptive children will not have the same DNA as their parents.
Likewise, hiding a visible element from a screen reader is something that you would not normally do. However, if the element is purposefully hidden and cannot be interacted with, it is OK to use the aria-hidden state.
EXAMPLES:
Don’t do this:
<button role=”presentation”>Click here</button> or
Applying aria-hidden to a parent/ancestor of a visible interactive element will also result in the interactive element being hidden. REAL LIFE SCENARIO: Children will inherit properties of their parents.
If an interactive element cannot be seen or interacted with, then you can apply aria-hidden, as long as it's not focusable:
If an interactive element is hidden using display:none or visibility:hidden on either the element itself or any of the element's anceestors, it won't be focusable, and it will aslo be removed from the accessibility tree which makes the addition of aria-hidden="true" or explicitly setting the tabindex="-1" unnecessary.
Rule #5: All ARIA elements must have accessible name
All interactive ARIA elements must have an accessible name based on its API accessible name (or equivalent), or its property has a value. EXAMPLE: Instead of doing this:
<label>user name</label><input type="text">
While the input field has a visible label, it does NOT have an accessible name. Do this:
Notice there are two ways to cause the element to have an accessible name.
Use the for/id attributes with the label and input elements (preferred)
Wrap the input with a label element.
NOTE: A div element regardless of what role is assigned to it is not an HTML labelable element. For example, <label> user name</label> <div role=”combobox”></div> will not yield an accessible name.