Element Inspection
element-inspector
Inspect and interact with GUI elements using platform accessibility APIs.
Overview
The @nut-tree/element-inspector plugin implements the ElementInspectionProviderInterface to enable inspection and interaction with GUI elements within windows. It uses platform accessibility APIs to find, query, and interact with UI elements.
Find Elements
Locate UI elements by role, title, type, or value
win.find(elements.menuItem({title: "File"}))Element Hierarchy
Inspect the full element tree of a window
win.getElements(5)Element Relations
Target nested elements with parent-child relations
in: elements.treeItem({title: ...})Installation
npm i @nut-tree/element-inspectorSubscription Required
Setup
Activate the plugin with useElementInspector() and import elements from the platform-specific subpath:
import { useElementInspector } from "@nut-tree/element-inspector";
// macOS
import { elements } from "@nut-tree/element-inspector/macos";
// Windows
import { elements } from "@nut-tree/element-inspector/win";
// Linux
import { elements } from "@nut-tree/element-inspector/linux";
useElementInspector();Retrieving Window Elements
Examine a window's element hierarchy using getElements():
const items = await win.getElements();
console.log(JSON.stringify(items, null, 2));Depth Limit
getElements() will return a maximum of 1000 elements. Pass a number to modify the amount of elements for better performance or more details.Element Structure
Each element contains:
interface WindowElement {
id?: string;
type?: string;
title?: string;
value?: string;
role?: string;
subRole?: string;
className?: string;
helpText?: string;
selectedText?: string;
clickablePoint?: Point;
region?: Region;
expandCollapsedState?: ExpandCollapseState;
isFocused?: boolean;
isEnabled?: boolean;
isVisible?: boolean;
isSelected?: boolean;
isChecked?: boolean;
isRequiredForForm?: boolean;
isKeyboardFocusable?: boolean;
isReadOnly?: boolean;
children?: WindowElement[];
};Finding Elements
Locate elements using WindowElementQuery objects with WindowElementDescription properties. Properties accept strings or RegExp patterns:
// Find a single element
const fileMenu = await win.find(elements.menuItem({ title: "File" }));
// Find all matching elements (returns empty array if none found)
const menuItems = await win.findAll(elements.menuItem({}));
// Wait for an element to appear
const menu = await win.waitFor(elements.menu({}));Property Matchers
Match elements by their properties. String properties also accept RegExp patterns:
id
id?: string | RegExpElement identifier
role
role?: stringAccessibility role of the element
type
type?: stringElement type
className
className?: string | RegExpCSS class name of the element
title
title?: string | RegExpElement title or label
value
value?: string | RegExpElement value
selectedText
selectedText?: string | RegExpCurrently selected text in the element
helpText
helpText?: string | RegExpHelp or tooltip text associated with the element
State Matchers
Match elements by their current state:
expandCollapsedState
expandCollapsedState?: "EXPANDED" | "COLLAPSED" | "TRANSITIONING"Expand/collapse state of the element
isFocused
isFocused?: booleanWhether the element currently has focus
isEnabled
isEnabled?: booleanWhether the element is enabled
isVisible
isVisible?: booleanWhether the element is visible
isChecked
isChecked?: booleanWhether the element is checked (checkboxes, radio buttons)
isSelected
isSelected?: booleanWhether the element is selected
isRequiredForForm
isRequiredForForm?: booleanWhether the element is required for form submission
isDataValidForForm
isDataValidForForm?: booleanWhether the element's data is valid for form submission
isKeyboardFocusable
isKeyboardFocusable?: booleanWhether the element can receive keyboard focus
isReadOnly
isReadOnly?: booleanWhether the element is read-only
// Find an enabled, visible checkbox that is checked
const checkbox = await win.find(elements.checkbox({
title: "Accept Terms",
isEnabled: true,
isVisible: true,
isChecked: true,
}));
// Find an expanded tree item
const expanded = await win.find(elements.treeItem({
title: "Documents",
expandCollapsedState: "EXPANDED",
}));Hierarchical Relations
Target elements based on their position in the element tree:
in
in?: WindowElementQueryDirect parent element (resolves innermost to outermost)
descendantOf
descendantOf?: WindowElementQueryAny ancestor element (not just direct parent)
ancestorOf
ancestorOf?: WindowElementQueryAny descendant element (not just direct child)
// Direct parent with 'in'
const dvdItem = await explorer.find(
elements.treeItem({
title: "boot",
in: elements.treeItem({
title: /DVD.*/,
in: elements.treeItem({ title: "Desktop" }),
}),
})
);
// Any ancestor with 'descendantOf'
const button = await win.find(elements.button({
title: "OK",
descendantOf: elements.dialog({ title: "Confirm" }),
}));Sibling Relations
Target elements relative to their siblings:
after
after?: WindowElementQueryThe element must appear after this sibling
before
before?: WindowElementQueryThe element must appear before this sibling
siblingOf
siblingOf?: WindowElementQueryThe element must be a sibling of this element
// Find a text field that appears after a label
const input = await win.find(elements.textField({
after: elements.staticText({ title: "Username" }),
}));
// Find the menu item before "Exit"
const item = await win.find(elements.menuItem({
before: elements.menuItem({ title: "Exit" }),
}));
// Find any button that is a sibling of a specific checkbox
const btn = await win.find(elements.button({
siblingOf: elements.checkbox({ title: "Remember me" }),
}));Position Modifiers
Narrow down matches by position among siblings:
nthChild
nthChild?: numberMatch the nth child (0-indexed)
firstChild
firstChild?: booleanMatch only the first child
lastChild
lastChild?: booleanMatch only the last child
// Get the third tab in a tab bar
const tab = await win.find(elements.tab({
nthChild: 2,
in: elements.tabGroup({}),
}));
// Get the first item in a list
const first = await win.find(elements.listItem({
firstChild: true,
in: elements.list({}),
}));
// Get the last menu item
const last = await win.find(elements.menuItem({
lastChild: true,
in: elements.menu({}),
}));Logic
Exclude elements from results:
notMatching
notMatching?: WindowElementQueryExclude elements that match this query
// Find all buttons except disabled ones
const buttons = await win.findAll(elements.button({
notMatching: elements.button({ isEnabled: false }),
}));
// Find menu items that are not separators
const items = await win.findAll(elements.menuItem({
notMatching: elements.menuItem({ role: "separator" }),
}));Factory Functions
The elements object provides platform-specific factory functions for creating element queries. Common functions include:
elements.menuItem({ title: "File" })
elements.menu({})
elements.button({ title: "OK" })
elements.textField({ value: "..." })
elements.treeItem({ title: "Documents" })
elements.checkbox({ title: "Enable" })For type-agnostic searching, use windowElementDescribedBy() instead.
Troubleshooting
Few or No Elements Returned
"editor.accessibilitySupport": "on" in its settings.Unstable Element Positions