I have jotted down some notes on ARIA concepts and usage that may be useful for developers.
Note: this information is now being actively maintained as part of Using ARIA in HTML.
The first rule of ARIA use
If you can use a native HTML element or attribute instead of an ARIA role, state or property, then do so.
Under what circumstances may this not be possible?
- If the visual design constraints rule out the use of a particular native element, because the element cannot be styled as required.
- If the feature is not currently available in HTML.
- If the feature is available in HTML but it is not implemented or it is implemented, but accessibility support is not.
The Second rule of ARIA use
Do not change native semantics, unless you really have to.
For example: Developer wants to build a heading that’s a button.
Do not do this:
<h1 role=button>heading button</h1>
Do this:
<h1><span role=button>heading button</span></h1>
Or better, do this:
<h1><button>heading button</button></h1>
Note: 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.
What does adding a role do to the native semantics?
Adding an ARIA role overrides the native role semantics.
For example:
<h1 role=button>text</h1>
Becomes this in the accessibility tree:
<button>text</button>
What adding a role does not do?
Adding an ARIA role does not change the behaviours, states and properties
For example:
This:
<button role=heading>
text</button>
Becomes this in the accessibility tree:
<heading>text</heading>
But it is can still be pressed, it is still in the default tab order, still looks like a button
, still triggers any associated actions when pressed. That’s why it is a HTML5 conformance error to change a button
into a heading
.
Note: likewise, changing the role of an element does not add behaviours, properties or states of the role used. You must add those yourself.
Add ARIA inline or via script?
If the ARIA role
or aria-*
attribute does not rely on scripting to provide interaction behaviour, then it is safe to include the ARIA markup inline. For example, it is fine to add ARIA landmark roles or ARIA labelling and describing roles inline. If the content and interaction is only supported in a scripting enabled browsing context, for example Google docs applications require JavaScript enabled to work, so it is safe for them to include the ARIA markup inline.
Otherwise add ARIA via scripting.
ARIA validation
The easiest method is to use the HTML5 DOCTYPE with ARIA markup and validate using the W3C Nu Markup Validation Service. ARIA works equally well with any other DOCTYPE, but validation tools will produce errors when they encounter ARIA markup as the associated DTDs have not been updated to recognise ARIA markup and it is unlikely they ever will be.
Use of role=presentation
role=presentation
removes the semantics from the element it is on.
For example.
This:
<h1 role=presentation>text</h1>
becomes this:
<>text</>
For elements with no required children, any elements nested inside the element with role=presentation
preserve their semantics.
For example.
This:
<h1 role=presentation><abbr>API</abbr></h1>
becomes this:
<><abbr>API</abbr></>
For elements with required children (such as ul or table any required child elements nested inside the element with role=presentation
also have their semantics removed.
For example,
This:
<table role=presentation>
<tr><td><abbr>API</abbr></td><tr>
</table>
becomes this:
<>
<><><abbr>API</abbr></></>
</>
Note: Any elements that are not required children of the element with a role=presentation keep their semantics. This includes other elements with required children.
For example;
<table role=presentation>
<tr><td>
<table>
<tr><td><abbr>API</abbr></td><tr>
</table>
</td><tr>
</table>
Becomes this:
<>
<><>
<table>
<tr><td><abbr>API</abbr></td><tr>
</table>
</><>
</>
aria-labelledby and aria-describedby
Currently aria-labelledby and
aria-describedby
are only robustly supported for associating text content to a subset of interactive content elements, they do not work correctly on links, support on embedded content is unknown, but can be safely used on form controls including the many input
types.
In Internet Explorer, if you use aria-labelledby
with multiple id
references or aria-describedby
with single or multiple id
references, the referenced elements must be what Microsoft terms as accessible HTML elements.
The following example of aria-labelledby
with multiple references uses the label
element as it makes sense and it’s an accessible element (in IE terms). The example could have used a span
(for example) but then tabindex=-1
would have to be added. Refer to Making Non accessible Elements Accessible
<label id="l1" for="f3">label text </label>
<input type="text" id="f3" aria-labelledby="l1 l2">
<p>other content</p>
<label id="l2">more label text</label>
Abstract roles
Do not use the following abstract roles as they do not do anything!
Abstract roles are used for the ontology. Authors MUST NOT not use abstract roles in content.
command
(abstract role)composite
(abstract role)input
(abstract role)landmark
(abstract role)range
(abstract role)roletype
(abstract role)section
(abstract role)sectionhead
(abstract role)select
(abstract role)structure
(abstract role)widget
(abstract role)window
(abstract role)
Comments
Great article Steve,
I found interesting the part about “Aria inline or via script”,
Could you add more information about dynamic content best practices? I found this example of adding ARIA via scripting:
https://www.w3.org/TR/WCAG20-TECHS/aria.html
Thanks
Thanks,
A nice highlight that roles change the semantics, makes perfect sense when you think about it!!