# Masonry/Xilem Accessibility Reference

This document summarizes how accessibility is supported by upstream
Masonry/Xilem. It is intended as a reference for custom widget authors, not as
an implementation plan for any specific tinymist-viewer feature.

The APIs described here are based on the `Myriad-Dreamin/xilem` revision pinned
by this workspace at the time this document was written.

## Overview

Masonry exposes accessibility through [AccessKit](https://accesskit.dev/).
Accessibility metadata is owned by Masonry widgets. Xilem does not provide a
separate accessibility description language; it builds and rebuilds Masonry
widgets, and Masonry produces the AccessKit tree from those widgets during its
accessibility pass.

For a custom component, the division of responsibility is:

- The Masonry `Widget` implementation declares the role, fills the AccessKit
  node, exposes supported accessibility actions, and handles accessibility
  action events.
- The Xilem `View` creates the widget, updates the widget state during rebuild,
  and ensures state changes request the correct Masonry pass.
- AccessKit is the platform-facing tree model. A widget can either expose a
  single node for itself or add additional synthetic AccessKit nodes for internal
  semantic structure.

Custom drawing does not expose internal semantics automatically. If painted
content contains meaningful structure, the widget must provide that structure as
accessibility metadata.

## Masonry Widget Hooks

Every custom Masonry widget implements `masonry::core::Widget`. The primary
accessibility-related hooks are:

- `accessibility_role`: returns the AccessKit `Role` for the widget node.
- `accessibility`: fills additional properties on the generated AccessKit
  `Node`.
- `on_access_event`: handles actions requested by assistive technologies.
- `children_ids`: reports child widget ids in accessibility order.
- `register_children`: registers child widgets with Masonry.

Masonry creates a fresh AccessKit node for each widget when accessibility is
updated, then calls the widget's `accessibility` method to let it fill in
widget-specific metadata. The widget should treat the passed node as ephemeral
and fully describe its current state each time the method is called.

## Framework-Provided Metadata

Before `Widget::accessibility` runs, Masonry has already populated framework
metadata that is derived from widget state and layout:

- The node role from `Widget::accessibility_role`.
- Bounds from the widget border box.
- Transform information from layout, placement, scrolling, and scaling.
- Children from `Widget::children_ids`, with stashed children excluded.
- Common state such as disabled, clipping, focus, and blur when applicable.

The widget's own `accessibility` method should add semantic properties that
Masonry cannot infer, such as names, descriptions, values, checked state,
selected state, text metadata, supported actions, or custom child nodes.

## Roles and Node Properties

`accessibility_role` should describe the semantic role, not the visual shape.
Common upstream patterns are:

- Purely drawn content with no internal semantic structure uses `Role::Canvas`
  or `Role::Image`, usually with a description when meaningful.
- Activatable controls use roles such as `Role::Button`, `Role::CheckBox`, or
  `Role::Switch`, and expose `Action::Click` when they can be activated.
- Adjustable controls use roles such as `Role::Slider`, `Role::ScrollBar`, or
  `Role::Splitter`, along with value, range, orientation, and increment or
  decrement actions.
- Scrollable containers use `Role::ScrollView`, scroll ranges, current scroll
  offsets, and scroll-related actions.
- Text-oriented widgets use text-capable roles and provide text values,
  character positions, selections, and supported text actions as needed.

The built-in Masonry widgets are the best reference for idiomatic role and
property combinations. For example, built-in controls pair their AccessKit role
with matching state properties and actions instead of relying on role alone.

## Accessibility Actions

If a node advertises an AccessKit action, the owning widget must handle the same
action in `on_access_event`.

Accessibility actions are delivered to Masonry with a target node id. For normal
widget nodes, the target corresponds to the widget. For synthetic nodes created
inside a widget, the owner widget is responsible for mapping the target node id
back to the appropriate internal semantic object.

Typical actions include:

- `Click` for activatable controls and links.
- `Focus` and blur-related behavior for focusable widgets.
- `Increment`, `Decrement`, or `SetValue` for adjustable controls.
- `ScrollIntoView` and scroll actions for scrollable content.
- Text actions for text editing, selection, and cursor movement when supported
  by the widget.

Action handling should produce the same observable behavior as the equivalent
keyboard or pointer interaction whenever possible.

## Requesting Updates

Masonry caches rendering and accessibility state. A widget must request the
appropriate pass when its state changes:

- `request_accessibility_update` when only accessibility metadata changed, such
  as a label, description, value, state, selection, or supported action.
- `request_render` when both visual output and accessibility metadata may have
  changed.
- `request_paint_only` when only paint output changed and the accessibility tree
  is still valid.
- `request_layout` when size, placement, or child structure changed. Layout
  changes can also affect accessibility because bounds, transforms, and children
  may change.

Choosing the narrowest correct request keeps Masonry's cached work valid without
skipping necessary accessibility updates.

## Children and Containers

A container widget must keep child registration, layout, and accessibility child
order consistent:

- `register_children` registers the child widgets.
- `layout` lays out and places the same children.
- `children_ids` returns the ids that should appear in the accessibility tree,
  in the order assistive technologies should traverse them.

If the set of child widgets changes dynamically, the parent must notify Masonry
that its children changed. Stashed children are not painted and are not exposed
in the accessibility tree.

## Synthetic AccessKit Nodes

A widget is not limited to one AccessKit node. When a single widget represents
structured content internally, it can create additional synthetic nodes during
the accessibility pass.

The upstream mechanism is:

- Allocate stable non-widget node ids through `AccessCtx`.
- Submit extra nodes through the AccessKit tree update available from
  `AccessCtx`.
- Attach the synthetic node ids as children of the widget node or of other
  synthetic nodes.
- Keep ids stable for semantic objects across updates so assistive technology
  focus and selection do not jump unnecessarily.

Synthetic nodes are useful when the visual implementation is a single custom
widget but the accessible representation needs finer structure, such as text
lines, text runs, list items, inline controls, or other semantic regions.

The owner widget remains responsible for update granularity, node id stability,
and action routing for any synthetic nodes it creates.

## Xilem Integration

Xilem `WidgetView` values build and rebuild Masonry widgets. Accessibility
metadata should still live in the Masonry widget, not in a parallel Xilem-only
model.

In Xilem, a custom view typically:

- Creates the widget pod during `build`.
- Registers action-capable widgets with the view context when Masonry actions
  should be routed back into the Xilem view tree.
- Compares old and new view inputs during `rebuild`.
- Calls widget helper methods through `WidgetMut` so the widget updates its
  state and requests the correct Masonry pass.

The view should pass accessibility-relevant input into the widget in the same
way it passes visual input. The widget then decides whether the change requires
layout, render, paint-only, or accessibility update work.

## Testing

Masonry accessibility behavior can be tested without relying only on screenshots.
Tests can inspect the produced accessibility tree and assert:

- Node roles.
- Names, descriptions, values, and state properties.
- Child ids and traversal order.
- Supported actions.
- Focusability and focus transitions.
- Tree changes after widget state updates.
- Action event behavior.

For custom widgets, these tests should cover the accessibility contract directly:
what assistive technologies see, what actions are exposed, and how the tree
changes when the widget state changes.

## References

- AccessKit: <https://accesskit.dev/>
- Masonry `Widget` trait:
  <https://docs.rs/masonry_core/latest/masonry_core/core/trait.Widget.html>
- Masonry custom widget tutorial:
  <https://docs.rs/masonry/latest/masonry/doc/doc_02_implementing_widget/index.html>
- ARIA roles reference:
  <https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles>
