AriaML Behavior Sheets
AriaML Behavior Sheets
AriaML Behavior Sheets
Introduction
AriaML Behavior technology introduces a declarative layer describing the behavior and relations between DOM elements. Unlike style sheets (CSS), behavior files (.bhv) do not handle appearance but actually modify the structure and state of the document.
The primary benefit is that the behavior of core interactive components (tabs, menus, accordions, etc.) can be defined in a purely declarative manner. Instead of writing scripts, the author describes relationships and behaviors. AriaML ensures that the accessibility tree and the physical DOM remain synchronized, notably by reacting to Media Queries (responsive), resolving, for example, the usual gap between visual order and keyboard navigation order.
1. Integration Model
1.1 .bhv Syntax
Behavior sheets use a declarative syntax inspired by CSS. Each block defines a selector and a set of behavior properties. These properties are injected into the semantic namespace of the corresponding elements.
1.2 Declaration
An AriaML document declares its resources via typed script tags, allowing for semantic isolation:
<script type="text/behavior" src="standard-patterns.bhv"></script>
<script type="text/behavior">
/* Local rules */
[role="tab"] { on-click: focus(next); }
</script>
2. Structural Reshuffling: The order Property
The order property is a real structural reshuffling instruction. Unlike its CSS counterpart, it does not merely change the visual display.
- Behavior: The User Agent physically reorders the child nodes of a parent based on their
ordervalue (ascending order, default is 0). - Purpose: To maintain strict correspondence between the reading flow (screen readers), tab order (keyboard focus), and visual position, especially in responsive interfaces.
3. Resolution System and Points of View (POV)
AriaML uses a trajectory engine to target elements without relying on unique identifiers (IDs), promoting reusability.
3.1 Base Points of View
| POV | Target |
|---|---|
| root | The root of the AriaML document. |
| self | The element holding the rule (default). |
| parent | The direct parent of the node. |
| siblings | Sibling nodes (excluding the element itself). |
| branch | All children of the parent (including the element). |
| closest: sel | The nearest ancestor matching selector sel. |
3.2 Navigation Relations
- next / prev: Direct adjacent elements in the DOM.
- first / last: The first or last child of the parent.
3.3 Declarative Relations (rel-*)
Authors can name complex relations to create semantic aliases.
- Definition:
rel-name: (POV) selector; - Usage: The
nameis then used as a target in actions.
4. Events and Lifecycle
AriaML distinguishes between standard DOM events and document lifecycle events.
- init: Triggered when the element is first discovered. Used for default role injections.
- on-apply: Triggered after every structural mutation or property update (e.g., after an
orderchange). - on-[event]: Standard events (click, input, change, etc.).
- on-clickout: Triggered when an interaction occurs outside the target element.
- on-current-change: A global event allowing reaction to changes in application state (e.g., page change or global selection).
- *Keyboard Accords (`kb-
)**: Captures key combinations. The nomenclature requires alphabetical order for modifiers (e.g.,kb-alt-shift-s`).
5. Interface Micro-Actions
Actions are atomic instructions that can be chained together.
5.1 State Mutations
- set(target@attr, "value"): Sets an attribute.
- set(target.class): Adds a class.
- rm(target@attr) / rm(target.class): Removes the attribute or class.
- toggle(target@attr, "v1", "v2", ...): Alternates between multiple values. If no values are specified, it acts as a boolean.
5.2 Flow and Focus
- focus(target): Moves the user focus.
- open(target) / close(target): Manages visibility. For
<dialog>elements, it uses native opening primitives. - open-modal(target): Opens a dialog with focus trapping (Focus Trap).
- trigger(target, "event"): Dispatches a custom event.
5.3 Tree Manipulation
- append(parent, child) / prepend(parent, child): Moves a node within the hierarchy.
- remove(target): Physically removes the node from the document.
6. Cross-Reference Patterns
6.1 Attribute Interpolation
Document data can be used to target elements via the #{attribute} syntax.
- Example:
rel-panel: (root) #{aria-controls};targets the element whose ID matches the value of thearia-controlsattribute on the current element.
6.2 Behavior Inheritance (behavior)
An element can inherit from a predefined pattern.
- Syntax:
behavior: pattern-name; - Local properties can override or supplement pattern properties using the
behavior()instruction.
A pattern is simply a set of grouped and predefined properties/values designed to streamline your behavior sheets by avoiding redundancy. You can view the available patterns in the JS implementation source code.
7. Examples
7.1 Responsive Semantics
AriaML allows for the redefinition of a component's structure and role based on the rendering context, without modifying the HTML.
@media (max-width: 600px) {
/* On mobile, the aside is at the end of the document for reading flow */
.sidebar {
order: 10;
role: region;
}
}
@media (min-width: 601px) {
/* On desktop, the aside physically moves before the content
to be the first tabbable element */
.sidebar {
order: -1;
role: navigation;
on-init: set(@aria-label, "Main Menu");
}
}
7.2 Navigation Menu Pattern (Burger)
This example illustrates how AriaML manages the state of a collapsible menu by synchronizing the button state (aria-expanded) with the target's visibility (hidden).
/* Menu control button */
button.burger {
/* Defining the relationship with the menu via its ID */
rel-menu: "(root) nav#main-menu";
/* Semantic initialization */
on-init:
set(self@aria-haspopup, "true")
set(self@aria-expanded, "false")
set(menu@hidden);
/* Menu toggle: the action toggles the state of both button and menu */
on-click:
toggle(self@aria-expanded, "true", "false")
toggle(menu@hidden);
/* Automatic closure if the user clicks outside */
on-clickout:
set(self@aria-expanded, "false")
set(menu@hidden);
/* Standard keyboard support */
kb-escape:
set(self@aria-expanded, "false")
set(menu@hidden)
focus(self);
}