hs.ax
ModuleAccessibility API Module
This module provides access to macOS's powerful Accessibility API, allowing you to:
- Inspect UI elements in any application
- Monitor window and element changes
- Programmatically interact with UI elements
Basic Usage
// Get the focused UI element
const element = hs.ax.focusedElement();
console.log(element.role, element.title);
// Watch an application's element for window creation events. Notifications bubble up
// from anywhere in the application's hierarchy, so this fires for every new window,
// not just one specific window.
const app = hs.application.frontmost();
hs.ax.on(app.axElement(), hs.ax.notificationTypes.windowCreated, (notification, element) => {
console.log("New window:", element.title);
});
// Watch a specific element (e.g. a text field found via findByRole) for value changes.
// Watching a specific element scopes the notification to just that element, rather
// than the whole application's hierarchy.
const field = hs.ax.findByRole(hs.ax.roles.textField, app.axElement())[0];
hs.ax.on(field, hs.ax.notificationTypes.valueChanged, (notification, element) => {
console.log("Field changed:", element.value);
});
Note: Requires accessibility permissions in System Preferences.
Types
This module provides the following types:
Properties
hs.ax.notificationTypes
{[key: string]: string}
A dictionary containing all of the notification types that can be used with hs.ax.on()
hs.ax.roles
{[key: string]: string}
A dictionary containing all of the known accessibility roles that elements can have, for use with hs.ax.findByRole() and similar
Methods
hs.ax.systemWideElement() -> HSAXElement
Get the system-wide accessibility element
Declaration
hs.ax.systemWideElement() -> HSAXElement
Returns
HSAXElement
The system-wide AXElement, or nil if accessibility is not available
Example
const sys = hs.ax.systemWideElement()
hs.ax.applicationElement(element) -> HSAXElement
Get the accessibility element for an application
Declaration
hs.ax.applicationElement(element) -> HSAXElement
Parameters
| Name | Type | Description |
|---|---|---|
| element | HSApplication | An HSApplication object |
Returns
HSAXElement
The AXElement for the application, or nil if accessibility is not available
Example
const app = hs.application.frontmost()
const ax = hs.ax.applicationElement(app)
hs.ax.windowElement(window) -> HSAXElement
Get the accessibility element for a window
Declaration
hs.ax.windowElement(window) -> HSAXElement
Parameters
| Name | Type | Description |
|---|---|---|
| window | HSWindow | An HSWindow object |
Returns
HSAXElement
The AXElement for the window, or nil if accessibility is not available
Example
const win = hs.window.focusedWindow()
const ax = hs.ax.windowElement(win)
hs.ax.elementAtPoint(point) -> HSAXElement
Get the accessibility element at the specific screen position
Declaration
hs.ax.elementAtPoint(point) -> HSAXElement
Parameters
| Name | Type | Description |
|---|---|---|
| point | HSPoint | An HSPoint object containing screen coordinates |
Returns
HSAXElement
The AXElement at that position, or nil if none found
Example
const el = hs.ax.elementAtPoint({x: 100, y: 200})
hs.ax.on(element, notification, listener) -> None
Register a listener for AX events on a specific element
Declaration
hs.ax.on(element, notification, listener) -> None
Parameters
| Name | Type | Description |
|---|---|---|
| element | HSAXElement | An HSAXElement to watch. Passing an application's element causes matching notifications to bubble up from anywhere in that application's hierarchy (e.g. AXWindowCreated for any window in the app, not just one); passing a specific descendant element scopes the notification to just that element |
| notification | JSValue | An event name, or an array of event names, to watch for with the same listener |
| listener | function | A function called with the notification name and the accessibility element it applies to |
Returns
None
Example
const app = hs.application.frontmost()
hs.ax.on(app.axElement(), hs.ax.notificationTypes.windowCreated, (notification, element) => {
console.log("New window:", element.title)
})
// Watch for several notifications with the same handler
hs.ax.on(app.axElement(), [hs.ax.notificationTypes.windowCreated, hs.ax.notificationTypes.windowMoved], (notification, element) => {
console.log(notification, element.title)
})
hs.ax.off(element, notification, listener) -> None
Remove a previously registered listener for AX events on a specific element
Declaration
hs.ax.off(element, notification, listener) -> None
Parameters
| Name | Type | Description |
|---|---|---|
| element | HSAXElement | The HSAXElement that was passed to `on` |
| notification | JSValue | The event name, or array of event names, to stop watching |
| listener | function | The function/lambda provided when adding the watcher |
Returns
None
Example
const app = hs.application.frontmost()
hs.ax.off(app.axElement(), hs.ax.notificationTypes.windowCreated, myHandler)
hs.ax.once(element, notification, listener) -> None
Register a listener that fires at most once for AX events on a specific element
Declaration
hs.ax.once(element, notification, listener) -> None
Parameters
| Name | Type | Description |
|---|---|---|
| element | HSAXElement | An HSAXElement to watch - see `on` for the application-vs-descendant bubbling behavior |
| notification | JSValue | An event name, or an array of event names, to watch for with the same listener |
| listener | function | Called once (per registered notification name), then automatically removed |
Returns
None
Example
const app = hs.application.frontmost()
hs.ax.once(app.axElement(), hs.ax.notificationTypes.windowCreated, (notification, element) => {
console.log("First new window:", element.title)
})
hs.ax.focusedElement() -> HSAXElement
Fetch the focused UI element
Declaration
hs.ax.focusedElement() -> HSAXElement
Returns
HSAXElement
An HSAXElement representing the focused UI element, or nil if none was found
Example
const el = hs.ax.focusedElement()
console.log(el.role + " " + el.title)
hs.ax.findByRole(role, parent) -> HSAXElement[]
Find AX elements matching a given role
Declaration
hs.ax.findByRole(role, parent) -> HSAXElement[]
Parameters
| Name | Type | Description |
|---|---|---|
| role | string | The role name to search for (e.g. "AXButton", or hs.ax.roles.button) |
| parent | HSAXElement | An HSAXElement to search within |
Returns
HSAXElement[]
An array of matching HSAXElement objects
Example
const app = hs.application.frontmost()
const buttons = hs.ax.findByRole(hs.ax.roles.button, app.axElement())
hs.ax.findByTitle(title, parent) -> HSAXElement[]
Find AX elements whose title contains a given string
Declaration
hs.ax.findByTitle(title, parent) -> HSAXElement[]
Parameters
| Name | Type | Description |
|---|---|---|
| title | string | The string to search for within element titles |
| parent | HSAXElement | An HSAXElement to search within |
Returns
HSAXElement[]
An array of matching HSAXElement objects
Example
const app = hs.application.frontmost()
const matches = hs.ax.findByTitle("OK", app.axElement())
hs.ax.printHierarchy(element, maxDepth) -> None
Print the accessibility hierarchy of an element to the Console
Declaration
hs.ax.printHierarchy(element, maxDepth) -> None
Parameters
| Name | Type | Description |
|---|---|---|
| element | HSAXElement | An HSAXElement to print. If omitted, the system-wide element is used |
| maxDepth | number | Maximum number of levels to traverse. Defaults to 5 |
Returns
None
Example
const app = hs.application.frontmost()
hs.ax.printHierarchy(app.axElement(), 3)