In what follows, let el.[[role]]
and el.[[aria-expanded]]
and the like be a fictional syntax for getting the true, screen-reader exposed ARIA values for an element. Let "no role" manifest as null
in JavaScript.
These code samples are meant to show how ARIA roles manifest themselves, both in an author-exposed way via attributes, and to screen-readers via the .[[true-values]]
. Seeing how these two interact is fairly enlightening.
- Has role
separator
by default.
var el = document.createElement("hr");
el.[[role]] === "separator";
el.getAttribute("role") === null;
el.setAttribute("role", "menuitem");
el.getAttribute("role") === "menuitem";
el.[[role]] === "menuitem";
el.removeAttribute("role");
el.[[role]] === "separator";
Similar situations with a default role: fieldset
, nav
, main
, ...
- Has no role by default.
var el = document.createElement("noscript");
el.[[role]] === null;
el.getAttribute("role") === null;
el.setAttribute("role", "menuitem");
el.getAttribute("role") === "menuitem";
el.[[role]] === "menuitem";
el.removeAttribute("role");
el.[[role]] === null;
Similar situations with no-role by default: meta
, param
, ...
- If it does not "create a hyperlink" (i.e., if it has no
href
attribute), then it has no special behavior or role. - If it has a
href
, then default role oflink
.
var el = document.createElement("a");
el.[[role]] === null;
el.setAttribute("role", "separator");
el.[[role]] === "separator";
el.href = "http://example.com/";
el.[[role]] === "separator";
el.removeAttribute("role");
el.getAttribute("role") === null;
el.[[role]] === "link";
el.removeAttribute("href");
el.[[role]] === null;
el.href = "http://example.com/";
el.[[role]] === "link";
Similar situations where the default role changes depending on various conditions: h1
with no hgroup
ancestor; select
with no multiple
attribute; img
with absent or nonempty alt
attribute...
aria-hidden
is set to"true"
by default.
el.[[aria-hidden]] === "true";
el.getAttribute("aria-hidden") === null;
el.setAttribute("aria-hidden", "false");
el.getAttribute("aria-hidden") === "false";
el.[[aria-hidden]] === "false";
Similar situations where a stoperty has a defualt vlaue: datalist
(aria-multiselectable
is "false"
), other non-visual elements like head
with their aria-hidden
, ...
aria-expanded
defaults to"true"
if theopen
attribute is present, and"false"
otherwise.
var el = document.createElement("details");
el.hasAttribute("open") === false;
el.[[aria-expanded]] === "false";
el.getAttribute("aria-expanded") === null;
el.setAttribute("open", "");
el.hasAttribute("open") === true;
el.[[aria-expanded]] === "true";
el.getAttribute("aria-expanded") === null;
el.setAttribute("aria-expanded", "false");
el.[[aria-expanded]] === "false";
el.hasAttribute("open") === true;
Similar situations where a stoperty is controlled by an HTML attribute: progress
, input
(readonly-ness), ...
aria-level
is by default set to the element's outline depth.
Code example left to your imagination, because moving things around different ouline depths is not fun to illustrate.