The easiest (and safest) way to manipulate ARIA attributes in HTML. Based on the W3C WAI-ARIA 1.2 Specification (published 6 June 2023).
npm i easy-aria
<script src="https://unpkg.com/easy-aria/dist/easy-aria.min.js"></script>
Simply call the aria()
function with an HTML Element or valid CSS selector, and use the methods exposed by the returned object.
Example:
import aria from 'easy-aria';
aria('#menu-btn')?.expand(); // Sets the `aria-expanded` attribute to `true`
The main function which returns a wrapped Element in an EasyAria
object. The Element can be accessed through the .el
property.
selector
- A valid CSS selector or HTML Element. If a selector is given, it is passed todocument.querySelector()
and the result is returned.
- The
EasyAria
instance which wraps the specified HTML Element, ornull
if a given selector does not match any element.
let ariaToolbar = aria('div#toolbar'); // CSS Selector
let menubar = document.getElementById('menubar');
let ariaMenubar = aria(menubar); // HTML Element
The wrapped HTML Element.
let button = document.createElement('button');
aria(button).el === button; // true
Sets the given ARIA attribute on the wrapped Element to the given value.
ℹ️ NOTE:
The
attribute
parameter only accepts the un-prefixed versions of allaria-*
attributes (i.e.,"aria-haspopup"
becomes"haspopup"
). This is done deliberately to make the code less verbose, as it is clear the context of attributes we want to manipulate.
attribute
- The ARIA attribute to set, without its"aria-"
prefix.value
- The value to assign to the given ARIA attribute.- The
value
argument is fully type-checked, and will only accept values supported by the given ARIA attribute. - The
value
argument only accepts the primitive equivalent of relevant attribute values (e.g.,aria-level
accepts anumber
;aria-atomic
accepts aboolean
;aria-hidden
accepts either aboolean
, or the literal string"undefined"
, etc.). - This argument can be omitted for attributes which accept a
boolean
value (e.g.,aria-atomic
oraria-hidden
). In that case, the implied value istrue
. - For attributes which require an IDREF (e.g.,
aria-activedescendant
), an HTMLElement
can be passed, as well as an arbitrarystring
. Anull
value does nothing, so the caller can directly pass the result of aquerySelector()
call. - For attributes which require a List of IDREFs (e.g.,
aria-controls
), the parameter accepts an arbitrarystring
, anElement
, anArray<Element>
,NodeList<Element>
, ornull
. The caller can directly pass the result of aquerySelectorAll()
call. - In the case of the above two points, if an element or collection of elements are passed to
value
, their IDs are retrieved and rendered as a string. If any element does not have an ID, one is generated and assigned to it.
- The
- The current
EasyAria
instance.
aria(button).set('label', 'Close'); // Sets `aria-label` to `Close`
aria(row).set('selected'); // Sets `aria-selected` to `true`
// <li id="id1" class="listitem">...</li>
// <li id="id2" class="listitem">...</li>
// <li id="id3" class="listitem">...</li>
aria(listbox).set('owns', document.querySelectorAll('.listitem'));
// Sets `aria-owns` to `"id1 id2 id3"`
Retrieves the given attribute's value from the wrapped Element.
ℹ️ NOTE:
The
attribute
parameter only accepts the un-prefixed versions of allaria-*
attributes (i.e.,"aria-haspopup"
becomes"haspopup"
). This is done deliberately to make the code less verbose, as it is clear the context of attributes we want to manipulate.
attribute
- The ARIA attribute whose value to retrieve, without its"aria-"
prefix.
- The parsed DOM-rendered value of the given attribute on the wrapped Element. Returns
null
if the attribute is not present, or its value is invalid*.- The return value is converted to the primitive equivalent of relevant attribute values (e.g.,
aria-level
returns anumber
;aria-atomic
returns aboolean
;aria-hidden
returns either aboolean
, or the literal string"undefined"
, etc.). - Currently, attributes which accept IDREF or a List of IDREFs will return their rendered string of ID(s), and not the elements themselves.
- * Parsing the DOM value is done strictly. That means, except for attributes which accept arbitrary strings—whose values are returned as is—values are strictly compared with their intended representation, and
null
is returned if they don't match. Hence, no whitespace around token strings is allowed, tokens are case-sensitive, and number values are cast withNumber()
, returningnull
if the result isNaN
.
- The return value is converted to the primitive equivalent of relevant attribute values (e.g.,
// <nav aria-label="Site">...</nav>
aria(nav).get('label'); // Returns "Site" (string)
// <tr aria-rowindex="8">...</tr>
aria(tr).get('rowindex'); // Returns 8 (number)
// <button aria-checked="false">...</button>
aria(button).get('checked'); // Returns false (boolean)
Removes the given ARIA attribute from the wrapped Element.
ℹ️ NOTE:
The
attribute
parameter only accepts the un-prefixed versions of allaria-*
attributes (i.e.,"aria-haspopup"
becomes"haspopup"
). This is done deliberately to make the code less verbose, as it is clear the context of attributes we want to manipulate.
attribute
- The ARIA attribute to remove, without its"aria-"
prefix.
- The current
EasyAria
instance.
// Before: <li id="opt-4" aria-selected="true">...</li>
aria(li).unset('selected');
// After: <li id="opt-4">...</li>
Sets the role
attribute on the wrapped Element to the given value.
value
- The value to set for therole
attribute. Supports full IntelliSense code-completion for all roles in the specification.
- The current
EasyAria
instance.
Returns the value of the role
attribute on the wrapped Element. It only considers the explicitly defined role attribute, and not the implied role based on element type.
- The value of the
role
attribute as astring
, ornull
if the attribute is absent.
Executes the given callback function, passing in the wrapped Element as an argument.
callbackFn
- The callback function to run, which receives the wrapped Element as its argument.
You can pass a function expression (i.e.,function(el) {...}
) to have access tothis
as the currentEasyAria
instance.
- The current
EasyAria
instance.
aria(button)
.call(el => (el.dataset.open = true))
.expand();
The .set()
, .setRole()
, .unset()
and .call()
methods, as well as all setter convenience methods return the current EasyAria
instance. This allows the caller to chain similar methods for simpler and more readable code.
Example:
aria('input#combo-1')
?.control('combo1-popup')
.set('autocomplete', 'list')
.set('activedescendant', 'option-1')
.expand();
This set of calls will cause the wrapped element to have the following HTML:
<input
id="combo-1"
aria-controls="combo1-popup"
aria-autocomplete="list"
aria-activedescendant="option-1"
aria-expanded="true"
...
/>
The EasyAria
class provides a set of convenience methods which further make the manipulation of many attributes easier. They are classified into Setter methods and Boolean methods.
These are defined as verbs, and call this.set()
under the hood. Setter methods can be chained, since they return the current instance after manipulation. Most of them require no arguments.
Method | Description |
---|---|
.check() |
Sets aria-checked to true . |
.uncheck() |
Sets aria-checked to false . |
.toggleChecked() |
Toggles the state of aria-checked between true and false . Sets it to true if its current value is neither. |
.control(value) |
Sets aria-controls to the given element ID(s). Equivalent to calling .set('controls', value) . |
.describeWith(value) |
Sets aria-describedby to the given element ID(s). Equivalent to calling .set('describedby', value) . |
.disable() |
Sets aria-disabled to true . |
.enable() |
Sets aria-disabled to false . |
.toggleDisabled() |
Toggles the state of aria-disabled between true and false . Sets it to true if its current value is neither. |
.expand() |
Sets aria-expanded to true . |
.collapse() |
Sets aria-expanded to false . |
.toggleExpanded() |
Toggles the state of aria-expanded between true and false . Sets it to true if its current value is neither. |
.flowTo(value) |
Sets aria-flowto to the given element ID(s). Equivalent to calling .set('flowto', value) . |
.grab() |
Sets aria-grabbed to true . |
.ungrab() |
Sets aria-grabbed to false . |
.toggleGrabbed() |
Toggles the state of aria-grabbed between true and false . Sets it to true if its current value is neither. |
.hide() |
Sets aria-hidden to true . |
.unhide() |
Sets aria-hidden to false . |
.toggleHidden() |
Toggles the state of aria-expanded between true and false . Sets it to true if its current value is neither. |
.label(value) |
Sets aria-label to the given string. |
.labelWith(value) |
Sets aria-labelledby to the given element ID(s). Equivalent to calling .set('labelledby', value) . |
.own(value) |
Sets aria-owns to the given element ID(s). Equivalent to calling .set('owns', value) . |
.press() |
Sets aria-pressed to true . |
.unpress() |
Sets aria-pressed to false . |
.togglePressed() |
Toggles the state of aria-pressed between true and false . Sets it to true if its current value is neither. |
.require() |
Sets aria-required to true . |
.unrequire() |
Sets aria-required to false . |
.toggleRequired() |
Toggles the state of aria-required between true and false . Sets it to true if its current value is neither. |
.select() |
Sets aria-selected to true . |
.unselect() |
Sets aria-selected to false . |
.toggleSelected() |
Toggles the state of aria-selected between true and false . Sets it to true if its current value is neither. |
Each of these methods returns a boolean
value, indicating whether the corresponding attribute has the value true
, or in a few cases, has a truthy value.
Method | Description |
---|---|
.isAtomic() |
Returns true if aria-atomic is set to true , otherwise returns false . |
.isBusy() |
Returns true if aria-busy is set to true , otherwise returns false . |
.isChecked() |
Returns true if aria-checked is set to true , otherwise returns false . |
.isCurrent([value]) |
If a value is given, returns true if aria-current is equal to that value, and false otherwise. If no value is given, returns true if aria-current is set to true , page , step , location , date or time .value should not be true , since it makes more sense to call the method without an argument in that case. |
.isDisabled() |
Returns true if aria-disabled is set to true , otherwise returns false . |
.isExpanded() |
Returns true if aria-expanded is set to true , otherwise returns false . |
.isGrabbed() |
Returns true if aria-grabbed is set to true , otherwise returns false . |
.hasPopup([value]) |
If a value is given, returns true if aria-haspopup is equal to that value, and false otherwise. If no value is given, returns true if aria-haspopup is set to true , menu , listbox , tree , grid or dialog .value should not be true , since it makes more sense to call the method without an argument in that case. |
.isHidden() |
Returns true if aria-hidden is set to true , otherwise returns false . |
.isInvalid([value]) |
If a value is given, returns true if aria-invalid is equal to that value, and false otherwise. If no value is given, returns true if aria-invalid is set to true , grammar or spelling .value should not be true , since it makes more sense to call the method without an argument in that case. |
.isModal() |
Returns true if aria-modal is set to true , otherwise returns false . |
.isMultiline() |
Returns true if aria-multiline is set to true , otherwise returns false . |
.isMultiselectable() |
Returns true if aria-multiselectable is set to true , otherwise returns false . |
.isPressed() |
Returns true if aria-pressed is set to true , otherwise returns false . |
.isReadonly() |
Returns true if aria-readonly is set to true , otherwise returns false . |
.isRequired() |
Returns true if aria-required is set to true , otherwise returns false . |
.isSelected() |
Returns true if aria-selected is set to true , otherwise returns false . |
Currently, aria-checked="mixed"
and aria-pressed="mixed"
are treated as falsy.
These methods are provided for the ease of manipulating ARIA attributes on HTML Elements. It does not verify conformance of the product to the ARIA specification. Authors therefore maintain the responsibility of ensuring the right attributes are used for the right ARIA role in order to conform to the specification.
Access the full specification at https://www.w3.org/TR/wai-aria-1.2/.
Remember, No ARIA is better than Bad ARIA.
Emmanuel Amoah ([email protected])
- LinkedIn: Emmanuel Amoah
- Instagram: @mystery.graphics