DARIA Extension Documentation: Declarative Accessible Rich Internet Applications
This documentation presents the initial specification of the DARIA language, a behavior sheet language designed to separate basic Web interactivity from JavaScript, thus making documents more robust and accessible by default.
Fundamental Principles of DARIA
- Declarative: Behavior is defined by rules and selectors, similar to CSS, describing how elements should interact.
- Accessibility by Default: The goal is to natively solve the ARIA Authoring Practices Guide patterns without relying on JavaScript.
- Separation of Concerns: DARIA is strictly limited to DOM manipulation (Attributes, Classes, ARIA). It does not handle style (domain of CSS) or complex application logic (domain of JavaScript).
Structure of a DARIA Behavior Sheet
A behavior sheet is composed of rules. Each rule begins with a selector (identical to CSS selectors) defining the targeted elements, followed by a block of declarations between curly braces.
There are mainly two types of rules: relations, prefixed by rel- and events, prefixed by on- or by kb- in the case of defining keyboard interactions.
The naming of relations can be arbitrary. It is recommended to choose a clear name (example: rel-controlled or rel-group).
selector {
rel-my-relationX: "my-selector"; /* Definition of relations */
rel-my-relationY: "my-other-selector";
on-eventName: micro-action1(my-relationX, param) micro-action2(my-relationY, param); /* Definition of behaviors */
kb-key1-key2: micro-action(my-relationY); /* Keyboard interactions */
/* ... */
}
Some special properties are under consideration. For example, the order property accepting an integer parameter. Unlike its CSS counterpart, this will involve actually moving the DOM elements based on the display context (media queries, breakpoints)
Declarative Relations
Relations are the key to DARIA; they allow linking the selected element to other target elements to apply actions. They are defined by the prefix rel-, followed by a name chosen by the integrator (e.g., rel-controlled, rel-button).
Relation Syntax
The value of a relation must be a string describing a selector, potentially prefixed by an initial point of view in parentheses.
By default, the initial point of view is the element captured by the selector. However, one may sometimes wish to establish a relation starting from one of its ancestors, or its direct ancestor.
rel-name: "selector-or-function";
Or:
rel-name: "(initial-pov) selector-or-function";
Predefined Initial Points of View (POV)
These keywords define the element from which the relation selector will be applied.
| POV | Description |
|---|---|
root | Document root (<html>). |
self | The element selected by the DARIA rule. |
parent | The direct parent element. |
next | The next sibling. |
prev | The previous sibling. |
branch | All children of the parent element. |
first | The first child of the parent element. |
last | The last child of the parent element. |
siblings | All siblings of the selected element (excluding the element itself). |
siblings: selector | Siblings matching the specified selector (excluding the element itself). |
closest: selector | The closest ancestor (or the element itself) matching the selector. |
Finally, the relation string can be calculated from one or more of its attributes in the same way as with CSS, using the attr() function.
Relation Examples:
#parent {
rel-relation: "#selector";
}
This relation is very simple. Note: its point of view is (by default) the "#parent" element. This means that #selector is assumed to be a descendant of #parent.
rel-controlled: "#" attr(aria-controls);
This relation is arbitrarily named "controlled". Its value is not immediately a string (presence of the attr() function) and must therefore be calculated. It will be defined by the content of the aria-controls attribute prefixed with "#".
rel-button: "(closest: #navigation) button[aria-controls=menu-principal]";
This last relation is a little more complex than the other two. Indeed, it does not start directly from the element captured by the selector, because it is prefixed by an initial point of view in parentheses which announces the first ancestor corresponding to "#navigation" as the starting point of the selection. Finally, the descendant(s) of "#navigation" that satisfy "button[aria-controls=menu-principal]" will be the element(s) ultimately targeted by the relation named "button".
Once the relations are defined, we will be able to apply behaviors to the elements targeted by these relations. This is the role of events and their micro-actions.
Micro-Actions and Events
The behavior of elements is defined via event properties (e.g., on-click) which contain a sequence of micro-actions executed synchronously.
Micro-Action Targeting
The target of a micro-action is the name of a relation or self, followed by the prefix @ for an attribute or a dot . for a class.
| Targeting | Description | Example |
|---|---|---|
relation@attribute | Targets an attribute on the elements linked by the relation. | set(controlled@hidden) |
relation.class | Targets a class on the elements linked by the relation. | rm(controlled.mobile) |
self@attribute | Targets an attribute on the selected element. | toggle(self@aria-expanded) |
Events
| Event | Description |
|---|---|
init | Executed once during the initial DOM parsing by the browser, or when the element (satisfying the selector) is inserted into the DOM. |
on-event | Refers to any user event (click, hover, etc.), except key presses. |
on-click-out | Synthetic event fired on a click outside the selected element and all elements linked by relations. |
kb-key(s) | Refers to the press of a key or a combination of keys (e.g., kb-escape, kb-shift-tab). |
List of Micro-Actions
These micro-actions form the basic vocabulary of DARIA.
They are the delicate boundary between a declarative language and a programming language. Their evolution must be strictly governed by a clear specification:
They will always be limited to a few basic DOM actions, whose implementation outside of JavaScript will allow for optimal and secure execution. They must never allow the execution of complex operations (loops, large calculations, or sending data outwards).
| Micro-Action | Syntax | Description |
|---|---|---|
set | set(target@boolean-attr)set(target@attr, "value")set(target.class) | Sets the value of an attribute or adds a class. |
rm | rm(target@attr)rm(target.class) | Removes an attribute or a class. |
toggle | toggle(target@attr)toggle(target@attr, "v1", "v2", "v3")toggle(target.class) | Inverts the state of an attribute/class or cycles through a list of values for an attribute. |
wait | wait(ms) | Pauses the execution of subsequent micro-actions for a number of milliseconds. |
cancel | cancel() | Prevents the default behavior of the event (equivalent to event.preventDefault()). |
trigger | trigger(target, "event-name") | Fires a custom DOM event (which can be listened to by JavaScript). |
open | open(target) | Opens an element (e.g., for <dialog>, JS equivalent: show()). |
open-modal | open-modal(target) | Opens an element in modal mode (e.g., for <dialog>, JS equivalent: showModal()). |
close | close(target) | Closes an element (e.g., for <dialog>, JS equivalent: close()). |
start-loop | start-loop(target, "name") | Starts a loop defined by the integrator (used for carousels, etc.). |
stop-loop | stop-loop(target, "name") | Stops an ongoing loop. |
prepend | prepend(parent-target, child-target) | Inserts an element as the first child. |
append | append(parent-target, child-target) | Inserts an element as the last child. |
scroll-to | scroll-to(viewport, target) | Scrolls an element (viewport) until the target is visible. |
Media Queries and Supports
DARIA rules can be conditioned by media queries or the native support for certain features.
Standard Media Queries
Standard media queries (such as @media (max-width: 1200px) or @media (prefers-reduced-motion: reduce)) are fully supported, allowing declarative behavior to adapt to user or device conditions.
@supports Rules
The @supports rule allows defining a declarative polyfill behavior if a native HTML feature is missing.
This feature will allow the browser to benefit from polyfills for possible recent HTML elements (e.g., invokers) even if JavaScript is disabled.
@supports not (details) {
/* DARIA rules to apply if the <details> tag is not supported */
}
@supports not (button[commandfor]) {
/* DARIA rules to apply if the <commandfor> attribute is not supported on buttons */
}
Example: Responsive Navigation Menu
Here is an example implementation of a navigation menu (with a button for mobile) that uses the ARIA attribute aria-expanded to indicate its state.
Default Behavior (Opening)
button[aria-expanded][aria-controls] {
rel-controlled: "#" attr(aria-controls); /* Links the button to the controlled menu */
init: set(self@hidden) rm(controlled@hidden) rm(controlled.mobile); /* Hides the button by default if the menu is visible (desktop state) */
}
Mobile Behavior (Reduced Screen)
@media (max-width: 1200px) {
button[aria-expanded][aria-controls] {
/* Initialization in mobile mode: the menu is hidden and the button is shown */
init: set(controlled@hidden) set(controlled.mobile) set(self@aria-expanded, "false") rm(self@hidden);
/* Click on the button: toggles the ARIA state and the hidden attribute of the menu */
on-click: toggle(self@aria-expanded, "true", "false") toggle(controlled@hidden);
/* Click outside the button/menu: closes the menu */
on-click-out: set(self@aria-expanded, "false") set(controlled@hidden);
/* Escape key (focus on the button): closes the menu */
kb-escape: set(self@aria-expanded, "false") set(controlled@hidden);
}
#menu-principal a {
rel-controlled: "(closest: #menu-principal)"; /* The anchor controls its parent menu */
rel-button: "(closest: #navigation) button[aria-controls=menu-principal]"; /* The anchor has a relation to the menu button */
/* Escape key (focus on an anchor in the menu): closes the menu */
kb-escape: set(button@aria-expanded, "false") set(controlled@hidden);
}
}
Roadmap
- Propose a specification draft as a starting point and subject for discussion (Drafting of this document is underway)
- Develop a JS polyfill of this specification to allow this language to exist independently of its adoption.
This implementation will serve as an experimental basis. It is currently under development.
It will come in a dual form:- A JS polyfill to embed DARIA support into HTML pages.
- A WebExtension allowing the user to disable JavaScript execution from visited pages ("Secured mode") while maintaining the experience offered by this implementation
- During the development of the DARIA language, new HTML tags based on the ARIA APG will undoubtedly be proposed. Furthermore, this language will also be used for the elaboration (outside of JavaScript) of polyfills for modern HTML elements (e.g., invokers). This is an argument in favor of secure navigation and the principle of progressive enhancement.
- After numerous discussions and sufficient coverage of the ARIA Authoring Practices Guide patterns, it will be time to encourage web developers as well as popular browser implementers to adopt DARIA.
Conclusion
Currently, the DARIA language is at an experimental stage.
Its definitive elaboration and standardization will have to rely on the approval of an open community: the DDEHTML working group of the W3C.
Its adoption will depend on its popularity among developers, and the goodwill of the implementers of each browser.
However, a JS implementation currently under development will by default allow this initiative to exist independently of its adoption.
If you wish to support this initiative, or simply wish to receive information on the evolution of this project, you can join this community.
A mailing list will soon be created, write to us to subscribe.