a11y

package
v0.1.13 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 8, 2026 License: MIT Imports: 4 Imported by: 0

Documentation

Overview

Package a11y provides accessibility foundation types for the gogpu/ui toolkit.

This package defines the interfaces and types needed to build an accessibility tree that can be consumed by platform-specific assistive technology adapters such as Windows UI Automation, macOS NSAccessibility, and Linux AT-SPI2.

The accessibility tree is a parallel semantic representation of the widget tree. Each widget that participates in accessibility implements the Accessible interface to provide its role, label, state, and supported actions. These are collected into Node instances that form a tree managed by a [Tree] implementation.

Architecture

The package follows a layered design inspired by AccessKit:

  • Role defines the semantic purpose of a UI element (button, checkbox, etc.)
  • Action defines operations assistive technology can perform on a node
  • State captures the dynamic accessibility state of a node
  • Accessible is the interface widgets implement to expose their semantics
  • Node is a tree node holding accessibility data with a stable NodeID
  • [Tree] manages the full accessibility tree with insert/remove/query operations
  • Announcer provides live region announcements for screen readers

Thread Safety

Node and [Tree] implementations are safe for concurrent access. They use sync.RWMutex internally to protect shared state. The Accessible interface methods should be called from the UI thread only.

Usage

Widgets expose their accessibility semantics by implementing Accessible:

type MyButton struct {
    widget.WidgetBase
    label string
}

func (b *MyButton) AccessibilityRole() a11y.Role   { return a11y.RoleButton }
func (b *MyButton) AccessibilityLabel() string      { return b.label }
func (b *MyButton) AccessibilityHint() string       { return "Activates the button" }
func (b *MyButton) AccessibilityValue() string      { return "" }
func (b *MyButton) AccessibilityState() a11y.State  { return a11y.State{} }
func (b *MyButton) AccessibilityActions() []a11y.Action {
    return []a11y.Action{a11y.ActionClick}
}

Platform adapters (Phase 4) will consume the tree to drive native accessibility APIs.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func BoolPtr

func BoolPtr(v bool) *bool

BoolPtr returns a pointer to the given boolean value.

This is a convenience function for setting the [State.Expanded] field:

state := a11y.State{
    Expanded: a11y.BoolPtr(true),  // expanded
}

func Float64Ptr

func Float64Ptr(v float64) *float64

Float64Ptr returns a pointer to the given float64 value.

This is a convenience function for setting numeric value fields:

state := a11y.State{
    ValueMin: a11y.Float64Ptr(0),
    ValueMax: a11y.Float64Ptr(100),
    ValueNow: a11y.Float64Ptr(50),
}

Types

type Accessible

type Accessible interface {
	// AccessibilityRole returns the semantic role of this element.
	//
	// The role determines how assistive technology presents the element
	// and what interactions are available. This should be stable for the
	// lifetime of the widget.
	AccessibilityRole() Role

	// AccessibilityLabel returns a human-readable label for this element.
	//
	// The label is the primary text that screen readers announce.
	// It should be concise and descriptive. For example, "Save" for a save button
	// or "Volume" for a volume slider.
	//
	// An empty string indicates the element has no explicit label.
	// Assistive technology may fall back to other sources (children, value, etc.).
	AccessibilityLabel() string

	// AccessibilityHint returns a description of the result of performing
	// the default action on this element.
	//
	// The hint provides additional context about what will happen when the user
	// activates the element. For example, "Opens the settings dialog" for a
	// settings button.
	//
	// An empty string indicates no hint is available.
	AccessibilityHint() string

	// AccessibilityValue returns the current value of this element as a string.
	//
	// This is used for elements that have a user-facing value, such as text fields
	// (the entered text), sliders (e.g., "50%"), and progress bars (e.g., "75% complete").
	//
	// An empty string indicates the element has no value to report.
	AccessibilityValue() string

	// AccessibilityState returns the current dynamic accessibility state.
	//
	// The state includes properties like disabled, selected, checked, expanded,
	// and numeric value range. These change as the user interacts with the element.
	AccessibilityState() State

	// AccessibilityActions returns the list of actions that assistive technology
	// can perform on this element.
	//
	// The returned slice should not be modified by the caller.
	// An empty or nil slice indicates the element supports no special actions.
	AccessibilityActions() []Action
}

Accessible is the interface that widgets implement to expose accessibility semantics.

Each method returns a snapshot of the widget's current accessibility state. Platform adapters query these methods to build and update the native accessibility tree consumed by screen readers and other assistive technology.

All methods must be safe to call from the UI thread. Implementations should not block or perform expensive operations.

Minimal Implementation

At minimum, a widget should provide a meaningful role and label:

func (b *Button) AccessibilityRole() a11y.Role  { return a11y.RoleButton }
func (b *Button) AccessibilityLabel() string     { return b.text }
func (b *Button) AccessibilityHint() string      { return "" }
func (b *Button) AccessibilityValue() string     { return "" }
func (b *Button) AccessibilityState() a11y.State { return a11y.State{} }
func (b *Button) AccessibilityActions() []a11y.Action {
    return []a11y.Action{a11y.ActionClick}
}

Rich Implementation

A slider widget provides full numeric value information:

func (s *Slider) AccessibilityRole() a11y.Role  { return a11y.RoleSlider }
func (s *Slider) AccessibilityLabel() string     { return s.label }
func (s *Slider) AccessibilityHint() string      { return "Adjusts the value" }
func (s *Slider) AccessibilityValue() string     { return fmt.Sprintf("%.0f%%", s.value*100) }
func (s *Slider) AccessibilityState() a11y.State {
    return a11y.State{
        ValueMin: a11y.Float64Ptr(float64(s.min)),
        ValueMax: a11y.Float64Ptr(float64(s.max)),
        ValueNow: a11y.Float64Ptr(float64(s.value)),
    }
}
func (s *Slider) AccessibilityActions() []a11y.Action {
    return []a11y.Action{a11y.ActionIncrement, a11y.ActionDecrement, a11y.ActionSetValue}
}

type Action

type Action uint8

Action represents an accessibility action that can be performed on a UI element.

Actions are the operations that assistive technology can invoke on behalf of the user. For example, a screen reader might trigger ActionClick when the user activates a button, or ActionSetValue when the user changes a slider value.

Widgets report their supported actions through [Accessible.AccessibilityActions]. Platform adapters translate these into platform-specific accessibility actions.

const (
	// ActionClick performs the default action for the element.
	// For buttons this triggers activation; for links this navigates.
	ActionClick Action = iota + 1

	// ActionFocus moves keyboard focus to the element.
	ActionFocus

	// ActionBlur removes keyboard focus from the element.
	ActionBlur

	// ActionSetValue sets the element's value.
	// This is used for text fields, sliders, and other value-bearing controls.
	ActionSetValue

	// ActionIncrement increases the element's value by one step.
	// This is used for sliders, spin buttons, and similar controls.
	ActionIncrement

	// ActionDecrement decreases the element's value by one step.
	// This is used for sliders, spin buttons, and similar controls.
	ActionDecrement

	// ActionExpand expands a collapsible element.
	// This is used for tree items, disclosure triangles, and similar controls.
	ActionExpand

	// ActionCollapse collapses an expanded element.
	// This is used for tree items, disclosure triangles, and similar controls.
	ActionCollapse

	// ActionSelect selects the element within its container.
	// This is used for list items, tabs, and similar selectable elements.
	ActionSelect

	// ActionScrollIntoView scrolls the element into the visible area
	// of its scroll container.
	ActionScrollIntoView

	// ActionScrollUp scrolls the content upward.
	ActionScrollUp

	// ActionScrollDown scrolls the content downward.
	ActionScrollDown

	// ActionScrollLeft scrolls the content to the left.
	ActionScrollLeft

	// ActionScrollRight scrolls the content to the right.
	ActionScrollRight

	// ActionShowContextMenu opens the element's context menu.
	ActionShowContextMenu

	// ActionDismiss dismisses a transient element such as a tooltip,
	// dialog, or popup menu.
	ActionDismiss
)

Action constants define standard accessibility actions.

The set of actions follows the AccessKit and WAI-ARIA action model.

func (Action) String

func (a Action) String() string

String returns a human-readable name for the action.

type Announcer

type Announcer interface {
	// Announce delivers a message to assistive technology.
	//
	// The message is spoken by the screen reader according to the given priority.
	// With [PriorityLow], the message waits for the current speech to finish.
	// With [PriorityHigh], the message interrupts current speech immediately.
	//
	// This method must be safe to call from any goroutine.
	Announce(message string, priority Priority)
}

Announcer is the interface for making live region announcements to assistive technology.

Live region announcements are used to notify screen readers of dynamic content changes that are not captured by the accessibility tree structure. For example, a chat application might announce new messages, or a form might announce validation errors.

Platform adapters provide implementations that use the native accessibility APIs. When no platform adapter is registered, NoOpAnnouncer is used.

Example

var announcer a11y.Announcer = a11y.NoOpAnnouncer{}
announcer.Announce("File saved successfully", a11y.PriorityLow)
announcer.Announce("Error: invalid input", a11y.PriorityHigh)

type CheckedState

type CheckedState uint8

CheckedState represents the checked state of a checkbox or similar control.

const (
	// CheckedFalse indicates the control is not checked.
	CheckedFalse CheckedState = iota

	// CheckedTrue indicates the control is checked.
	CheckedTrue

	// CheckedMixed indicates the control is in a mixed/indeterminate state.
	// This is used when a checkbox represents a group where some items
	// are checked and some are not.
	CheckedMixed
)

Checked state constants.

func (CheckedState) String

func (c CheckedState) String() string

String returns a human-readable name for the checked state.

type MemoryTree

type MemoryTree struct {
	// contains filtered or unexported fields
}

MemoryTree is an in-memory implementation of TreeProvider.

It stores the full accessibility tree with an index for O(1) node lookups by ID. It tracks dirty (changed) nodes for efficient platform synchronization.

Thread Safety:

MemoryTree is safe for concurrent access. All operations are protected by a sync.RWMutex.

func NewMemoryTree

func NewMemoryTree(root *Node) *MemoryTree

NewMemoryTree creates a new in-memory accessibility tree with the given root node.

The root node is registered in the tree's ID index. Pass nil to create an empty tree (Root will return nil until a root is inserted).

Example:

root := a11y.NewNode(a11y.RoleWindow, "My Application")
tree := a11y.NewMemoryTree(root)

func (*MemoryTree) ClearDirty

func (t *MemoryTree) ClearDirty()

ClearDirty clears the set of dirty nodes.

func (*MemoryTree) DirtyNodes

func (t *MemoryTree) DirtyNodes() []*Node

DirtyNodes returns the set of nodes marked as changed since the last call to ClearDirty.

func (*MemoryTree) Insert

func (t *MemoryTree) Insert(parent *Node, child *Node)

Insert adds a child node under the given parent.

Both parent and child must be non-nil. The child is appended to the parent's children list and registered in the ID index.

func (*MemoryTree) Len

func (t *MemoryTree) Len() int

Len returns the total number of nodes in the tree.

func (*MemoryTree) NodeByID

func (t *MemoryTree) NodeByID(id NodeID) *Node

NodeByID looks up a node by its unique identifier.

Returns nil if no node with the given ID exists.

func (*MemoryTree) Remove

func (t *MemoryTree) Remove(node *Node)

Remove removes a node and all its descendants from the tree.

If the removed node is the root, the tree becomes empty.

func (*MemoryTree) Root

func (t *MemoryTree) Root() *Node

Root returns the root node of the tree, or nil if the tree is empty.

func (*MemoryTree) Update

func (t *MemoryTree) Update(node *Node)

Update marks a node as changed for the next platform sync cycle.

func (*MemoryTree) Walk

func (t *MemoryTree) Walk(fn func(*Node) bool)

Walk performs a depth-first traversal of the tree.

If fn returns false, the traversal stops immediately.

type NoOpAnnouncer

type NoOpAnnouncer struct{}

NoOpAnnouncer is a default Announcer that discards all announcements.

It is used as the default announcer when no platform adapter is registered. This ensures code that makes announcements does not need nil checks.

NoOpAnnouncer is safe for concurrent use.

func (NoOpAnnouncer) Announce

func (NoOpAnnouncer) Announce(_ string, _ Priority)

Announce discards the message. This is a no-op implementation.

type Node

type Node struct {
	// contains filtered or unexported fields
}

Node represents a single element in the accessibility tree.

Each Node has a stable NodeID for identification, a Role for semantics, and optional properties like label, hint, value, state, bounds, and actions. Nodes form a tree structure through parent-child relationships.

Nodes are safe for concurrent access. All reads and writes are protected by a sync.RWMutex.

Creating Nodes

Create a node with NewNode or NewNodeFromAccessible:

node := a11y.NewNode(a11y.RoleButton, "Save")
node.SetHint("Saves the current document")
node.SetActions([]a11y.Action{a11y.ActionClick})

Tree Relationships

Nodes maintain parent-child relationships. Use [Tree.Insert] and [Tree.Remove] to manage the tree structure rather than manipulating parent/children directly.

func NewNode

func NewNode(role Role, label string) *Node

NewNode creates a new accessibility node with the given role and label.

The node is assigned a unique NodeID automatically.

Example:

node := a11y.NewNode(a11y.RoleButton, "OK")

func NewNodeFromAccessible

func NewNodeFromAccessible(a Accessible) *Node

NewNodeFromAccessible creates a new accessibility node populated from the given Accessible widget.

The node copies all properties from the widget and stores a reference to it for future updates via Node.SyncFromSource.

Example:

var button Accessible = myButton
node := a11y.NewNodeFromAccessible(button)

func (*Node) Actions

func (n *Node) Actions() []Action

Actions returns the node's supported accessibility actions.

The returned slice is a copy and safe to modify.

func (*Node) Bounds

func (n *Node) Bounds() geometry.Rect

Bounds returns the node's bounding rectangle in screen coordinates.

func (*Node) ChildCount

func (n *Node) ChildCount() int

ChildCount returns the number of child nodes.

func (*Node) Children

func (n *Node) Children() []*Node

Children returns a copy of the node's child nodes.

The returned slice is safe to modify without affecting the node.

func (*Node) Hint

func (n *Node) Hint() string

Hint returns the node's hint text.

func (*Node) ID

func (n *Node) ID() NodeID

ID returns the node's unique identifier.

The ID is assigned at creation and never changes.

func (*Node) Label

func (n *Node) Label() string

Label returns the node's label text.

func (*Node) Parent

func (n *Node) Parent() *Node

Parent returns the node's parent, or nil if this is the root node.

func (*Node) Role

func (n *Node) Role() Role

Role returns the node's accessibility role.

func (*Node) SetActions

func (n *Node) SetActions(actions []Action)

SetActions sets the node's supported accessibility actions.

func (*Node) SetBounds

func (n *Node) SetBounds(bounds geometry.Rect)

SetBounds sets the node's bounding rectangle.

func (*Node) SetHint

func (n *Node) SetHint(hint string)

SetHint sets the node's hint text.

func (*Node) SetLabel

func (n *Node) SetLabel(label string)

SetLabel sets the node's label text.

func (*Node) SetRole

func (n *Node) SetRole(role Role)

SetRole sets the node's accessibility role.

func (*Node) SetSource

func (n *Node) SetSource(a Accessible)

SetSource sets the Accessible widget backing this node.

func (*Node) SetState

func (n *Node) SetState(state State)

SetState sets the node's accessibility state.

func (*Node) SetValue

func (n *Node) SetValue(value string)

SetValue sets the node's current value.

func (*Node) Source

func (n *Node) Source() Accessible

Source returns the Accessible widget backing this node, or nil.

func (*Node) State

func (n *Node) State() State

State returns the node's current accessibility state.

func (*Node) String

func (n *Node) String() string

String returns a human-readable representation of the node.

func (*Node) SyncFromSource

func (n *Node) SyncFromSource() bool

SyncFromSource updates the node's properties from its source Accessible.

If the node has no source, this is a no-op and returns false. Returns true if the node was updated.

func (*Node) Value

func (n *Node) Value() string

Value returns the node's current value as a string.

type NodeID

type NodeID uint64

NodeID is a stable unique identifier for an accessibility tree node.

NodeIDs are generated by NextNodeID using an atomic counter, ensuring uniqueness within a process. They are uint64 values that remain stable across tree updates, which is critical for platform accessibility APIs that track nodes by ID.

A zero NodeID is invalid and indicates an uninitialized node.

func NextNodeID

func NextNodeID() NodeID

NextNodeID returns a new unique NodeID.

IDs are generated from an atomic counter starting at 1, ensuring they are unique within the process lifetime. This function is safe to call from any goroutine.

func (NodeID) IsValid

func (id NodeID) IsValid() bool

IsValid returns true if the node ID is not zero.

A zero NodeID indicates an uninitialized or invalid node.

func (NodeID) String

func (id NodeID) String() string

String returns a string representation of the node ID.

type Priority

type Priority uint8

Priority represents the urgency of a live region announcement.

The priority determines how screen readers handle the announcement relative to what they are currently speaking.

const (
	// PriorityLow indicates the announcement can wait until the screen reader
	// finishes its current speech. This is appropriate for non-urgent status
	// updates (equivalent to ARIA aria-live="polite").
	PriorityLow Priority = iota

	// PriorityHigh indicates the announcement should interrupt current speech.
	// This is appropriate for urgent messages like errors or alerts
	// (equivalent to ARIA aria-live="assertive").
	PriorityHigh
)

Priority constants.

func (Priority) String

func (p Priority) String() string

String returns a human-readable name for the priority.

type Role

type Role uint8

Role represents the semantic purpose of a UI element for assistive technology.

Roles are derived from the WAI-ARIA specification and AccessKit. They tell screen readers and other assistive technology how to present and interact with each element. Every accessible node must have exactly one role.

The role determines what properties, states, and actions are valid for a node. For example, a RoleSlider node is expected to have numeric value properties, while a RoleButton node supports a click action.

const (
	// RoleUnknown indicates an element whose role is not known.
	// This should only be used as a fallback when no other role applies.
	RoleUnknown Role = iota

	// RoleWindow represents a top-level application window.
	RoleWindow

	// RoleGroup represents a generic grouping of related elements.
	RoleGroup

	// RoleSeparator represents a visual or logical divider between sections.
	RoleSeparator

	// RoleToolbar represents a collection of commonly used function buttons
	// or controls.
	RoleToolbar

	// RoleStatusBar represents a bar that displays status information,
	// typically at the bottom of a window.
	RoleStatusBar

	// RoleMenuBar represents a horizontal bar containing menu items.
	RoleMenuBar

	// RoleGenericContainer represents a container with no specific semantics.
	// Use [RoleGroup] instead when elements are logically related.
	RoleGenericContainer
)

Structural roles define the layout and organization of the UI.

const (
	// RoleButton represents a clickable button that triggers an action.
	RoleButton Role = iota + 20

	// RoleCheckbox represents a control with checked, unchecked, or mixed state.
	RoleCheckbox

	// RoleRadio represents a radio button within a group where only one
	// can be selected at a time.
	RoleRadio

	// RoleTextField represents a single-line text input field.
	RoleTextField

	// RoleTextArea represents a multi-line text input field.
	RoleTextArea

	// RoleSlider represents a control for selecting a value from a continuous range.
	RoleSlider

	// RoleSwitch represents a toggle control with on/off state.
	RoleSwitch

	// RoleComboBox represents a composite widget combining a text field with
	// a popup list of choices.
	RoleComboBox

	// RoleSpinButton represents a numeric input with increment/decrement controls.
	RoleSpinButton

	// RoleRadioGroup represents a group of radio buttons where only one
	// can be selected.
	RoleRadioGroup

	// RoleSearchBox represents a text field specifically for search input.
	RoleSearchBox

	// RoleToggleButton represents a button that can be toggled on or off.
	RoleToggleButton

	// RoleColorWell represents a control for selecting a color value.
	RoleColorWell
)

Input roles define interactive elements that accept user input.

const (
	// RoleLabel represents a text label, often associated with a form control.
	RoleLabel Role = iota + 50

	// RoleImage represents a graphical image.
	RoleImage

	// RoleProgressBar represents a progress indicator showing completion
	// of a long-running operation.
	RoleProgressBar

	// RoleTooltip represents a small popup that provides additional context
	// when hovering over an element.
	RoleTooltip

	// RoleAlert represents an important message that demands the user's attention.
	RoleAlert

	// RoleBadge represents a small status descriptor, such as a notification count.
	RoleBadge

	// RoleHeading represents a heading that labels a section of content.
	RoleHeading

	// RoleMeter represents a scalar measurement within a known range,
	// such as disk usage or a gauge.
	RoleMeter

	// RoleStaticText represents non-interactive text content.
	RoleStaticText
)

Display roles define elements that present information to the user.

const (
	// RoleDialog represents a modal or non-modal dialog window.
	RoleDialog Role = iota + 70

	// RoleAlertDialog represents a dialog that conveys an urgent message
	// and requires user response.
	RoleAlertDialog

	// RoleMenu represents a popup menu offering a list of choices.
	RoleMenu

	// RoleMenuItem represents a single item within a menu.
	RoleMenuItem

	// RoleMenuItemCheckbox represents a checkable menu item.
	RoleMenuItemCheckbox

	// RoleMenuItemRadio represents a radio-selectable menu item within a group.
	RoleMenuItemRadio

	// RoleList represents an ordered or unordered list of items.
	RoleList

	// RoleListItem represents a single item within a list.
	RoleListItem

	// RoleTree represents a hierarchical tree view.
	RoleTree

	// RoleTreeItem represents a single item within a tree view.
	RoleTreeItem

	// RoleTab represents a selectable tab within a tab list.
	RoleTab

	// RoleTabList represents a list of tabs for switching between panels.
	RoleTabList

	// RoleTabPanel represents the content panel associated with a tab.
	RoleTabPanel

	// RoleGrid represents a two-dimensional grid of interactive cells.
	RoleGrid

	// RoleGridCell represents a single cell within a grid.
	RoleGridCell

	// RoleTable represents a data table with rows and columns.
	RoleTable

	// RoleRow represents a row within a table or grid.
	RoleRow

	// RoleCell represents a single cell within a table row.
	RoleCell

	// RoleColumnHeader represents a header cell for a table column.
	RoleColumnHeader

	// RoleRowHeader represents a header cell for a table row.
	RoleRowHeader

	// RoleListBox represents a list widget from which the user can select
	// one or more items.
	RoleListBox

	// RoleScrollView represents a scrollable container.
	RoleScrollView

	// RoleApplication represents a region declared as a web application
	// (used for complex interactive widgets).
	RoleApplication

	// RoleDocument represents a document content region.
	RoleDocument

	// RoleFeed represents a scrollable list of articles that grows dynamically.
	RoleFeed
)

Container roles define elements that contain and organize other elements.

const (
	// RoleLink represents a navigational hyperlink.
	RoleLink Role = iota + 110

	// RoleScrollBar represents a scrollbar control.
	RoleScrollBar

	// RoleNavigation represents a navigation landmark region.
	RoleNavigation

	// RoleBanner represents a banner landmark region, typically site-wide.
	RoleBanner

	// RoleMain represents the main content landmark region.
	RoleMain

	// RoleContentInfo represents informational content about the page,
	// typically a footer.
	RoleContentInfo

	// RoleComplementary represents a complementary landmark region
	// that supports the main content.
	RoleComplementary

	// RoleRegion represents a generic landmark region of significance.
	RoleRegion

	// RoleForm represents a form landmark region.
	RoleForm

	// RoleSearch represents a search landmark region.
	RoleSearch
)

Navigation roles define elements that help the user navigate the UI.

func (Role) IsContainer

func (r Role) IsContainer() bool

IsContainer returns true if the role represents an element that contains other accessible elements, such as dialogs, lists, and tables.

func (Role) IsInteractive

func (r Role) IsInteractive() bool

IsInteractive returns true if the role represents an element that accepts user input, such as buttons, text fields, and sliders.

func (Role) IsLandmark

func (r Role) IsLandmark() bool

IsLandmark returns true if the role represents a navigational landmark region, such as main content, navigation, or search.

func (Role) String

func (r Role) String() string

String returns a human-readable name for the role.

The returned string matches the role constant name without the "Role" prefix. For example, RoleButton returns "Button" and RoleCheckbox returns "Checkbox".

type State

type State struct {
	// Disabled indicates the element cannot be interacted with.
	// Disabled elements are still visible and present in the accessibility tree.
	Disabled bool

	// Selected indicates the element is currently selected within a group
	// (e.g., a selected list item or tab).
	Selected bool

	// Checked indicates the checked state for checkboxes, radio buttons,
	// and similar controls.
	Checked CheckedState

	// Expanded indicates whether an expandable element is expanded or collapsed.
	// nil means the element is not expandable.
	Expanded *bool

	// ReadOnly indicates the element's value cannot be modified by the user,
	// but the content can still be read and focused.
	ReadOnly bool

	// Required indicates the element must have a value before a form can
	// be submitted.
	Required bool

	// Busy indicates the element is being modified and assistive technology
	// should wait before exposing changes to the user.
	Busy bool

	// Hidden indicates the element should be excluded from the accessibility tree.
	// Hidden elements are not visible to assistive technology.
	Hidden bool

	// Focused indicates the element currently has keyboard focus.
	Focused bool

	// Modal indicates the element is a modal dialog that restricts interaction
	// to its descendants.
	Modal bool

	// Multiselectable indicates the element allows selecting multiple items.
	Multiselectable bool

	// ValueMin is the minimum allowed numeric value, or nil if not applicable.
	ValueMin *float64

	// ValueMax is the maximum allowed numeric value, or nil if not applicable.
	ValueMax *float64

	// ValueNow is the current numeric value, or nil if not applicable.
	ValueNow *float64

	// ValueText is a human-readable representation of the current value.
	// For a slider, this might be "50%" or "Medium". When empty, assistive
	// technology will typically use the numeric value.
	ValueText string

	// Level indicates the heading level (1-6) or tree item depth.
	// Zero means no level is applicable.
	Level int
}

State holds the dynamic accessibility state of a UI element.

State is a value type that captures a snapshot of an element's current accessibility-relevant properties. It is returned by [Accessible.AccessibilityState] and stored in Node instances for the accessibility tree.

All fields have meaningful zero values: the zero State represents an enabled, unchecked, visible, non-expandable element with no numeric value.

Expandable Elements

The Expanded field uses a *bool to distinguish between three cases:

  • nil: the element is not expandable (e.g., a button)
  • *false: the element is expandable but currently collapsed (e.g., a closed tree node)
  • *true: the element is expandable and currently expanded

Numeric Values

ValueMin, ValueMax, and ValueNow use *float64 to indicate whether numeric value semantics apply. When all are nil, the element has no numeric value (e.g., a button). When set, they describe a range (e.g., a slider from 0 to 100).

func (State) HasNumericValue

func (s State) HasNumericValue() bool

HasNumericValue returns true if the state has numeric value semantics.

This is true when at least one of ValueMin, ValueMax, or ValueNow is set.

func (State) IsExpandable

func (s State) IsExpandable() bool

IsExpandable returns true if the state represents an expandable element.

This is true when Expanded is not nil.

func (State) IsExpanded

func (s State) IsExpanded() bool

IsExpanded returns true if the state represents an expanded element.

Returns false if the element is not expandable or is collapsed.

type TreeProvider

type TreeProvider interface {
	// Root returns the root node of the accessibility tree.
	//
	// The root node typically represents the application window.
	// Returns nil if the tree is empty.
	Root() *Node

	// NodeByID looks up a node by its unique identifier.
	//
	// Returns nil if no node with the given ID exists in the tree.
	NodeByID(id NodeID) *Node

	// Update marks a node as having changed, so platform adapters can
	// send appropriate change notifications to assistive technology.
	//
	// This does not modify the node's properties; it only flags the node
	// for the next sync cycle. If the node has a source [Accessible],
	// callers should call [Node.SyncFromSource] before or after Update.
	Update(node *Node)

	// Insert adds a child node under the given parent.
	//
	// The child is appended to the parent's children list and registered
	// in the tree's ID index. If the child already has a parent, it is
	// not re-parented automatically; call [TreeProvider.Remove] first.
	Insert(parent *Node, child *Node)

	// Remove removes a node and all its descendants from the tree.
	//
	// The node is detached from its parent and unregistered from the
	// tree's ID index. Removing the root node empties the tree.
	Remove(node *Node)

	// Walk performs a depth-first traversal of the tree, calling fn
	// for each node. If fn returns false, the traversal stops immediately.
	//
	// The traversal visits the parent before its children.
	Walk(fn func(*Node) bool)

	// Len returns the total number of nodes in the tree.
	Len() int

	// DirtyNodes returns the set of nodes that have been marked as changed
	// since the last call to ClearDirty.
	//
	// The returned slice is a copy and safe to modify.
	DirtyNodes() []*Node

	// ClearDirty clears the set of dirty nodes.
	//
	// This is called by platform adapters after processing all pending
	// change notifications.
	ClearDirty()
}

TreeProvider is the interface for managing the accessibility tree.

The accessibility tree is a hierarchical representation of all accessible elements in the UI. Platform adapters consume this tree to drive native accessibility APIs (Windows UI Automation, macOS NSAccessibility, Linux AT-SPI2).

Implementations must be safe for concurrent access. The default implementation MemoryTree uses a sync.RWMutex.

Tree Lifecycle

  1. Create a tree with a root node
  2. As widgets are created, insert nodes with [TreeProvider.Insert]
  3. As widgets are updated, call [TreeProvider.Update] to mark changes
  4. As widgets are removed, call [TreeProvider.Remove]
  5. Platform adapters walk the tree with [TreeProvider.Walk]

Example

tree := a11y.NewMemoryTree(rootNode)
tree.Insert(rootNode, childNode)
tree.Walk(func(n *a11y.Node) bool {
    fmt.Printf("%s: %s\n", n.Role(), n.Label())
    return true // continue walking
})

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL