Supported Element Target Forms for Resolution in ego-browser: Complete Reference Guide

The ego-browser package supports 13 distinct element target forms including CSS selectors, XPath expressions, text/label/placeholder/alt/title/testid matchers, href locators, ARIA role selectors, and internal scoped/filtered queries.

The ego-browser library provides a powerful element resolution system for browser automation. Understanding the supported element target forms for resolution is essential for writing reliable selectors that work across diverse web interfaces. This guide covers every selector type recognized by the parseLocator function in src/element-resolver.ts.

Internal Query Selectors: Scoped and Filtered Resolution

The most advanced target forms use the internal: prefix to create composable, scoped queries.

Internal Scope Queries

Internal scope queries allow you to define a base element and a child selector as a single target. In src/element-resolver.ts, the parser detects internal:scope: and returns {kind: "query", …} for downstream resolution.

// Scope query: find button inside #parent
await ego.cdp('internal:scope:{"base":"#parent","child":"button"}');

Internal Filter Queries

Internal filter queries add visibility and content constraints. The parser recognizes internal:filter: at lines 31-33 and constructs complex filter objects.

// Filter query: section containing "Welcome" text
await ego.cdp('internal:filter:{"base":"section","hasText":{"text":"Welcome"}}');

Nth Modifiers: Position-Based Selection

The parseLocator function in src/element-resolver.ts extracts optional nth modifiers before primary parsing (lines 17-23). These let you target specific match positions.

Modifier Syntax Purpose
nth=N internal:nth=2;css:#btn Select the Nth match (1-indexed)
last internal:last;xpath=//div Select the final match

CSS Selectors: Standard and Shorthand Forms

CSS selectors are the default resolution strategy. The parser handles both explicit and implicit forms at lines 36-39.

// Explicit CSS with loc= prefix
await ego.cdp('loc=css:.my-class');

// Shorthand (no prefix)
await ego.cdp('.my-class');

When no recognized prefix is detected and nth is present, the system falls back to CSS selector resolution (lines 112-117).

XPath Selectors: Precise DOM Navigation

XPath expressions provide powerful DOM traversal. Detected by the xpath= prefix at lines 40-44.

await ego.cdp('xpath=//div[@id="root"]');
await ego.cdp('xpath=//a[contains(@href, "/settings")]');

Href Selectors: Exact Path Matching

Href selectors resolve elements by their href attribute value. Recognized at lines 45-48 with the href: prefix.

await ego.cdp('href:/login');
await ego.cdp('href:/dashboard');

Text Selectors: Visible Content Matching

The parseLocator function handles text selectors through two syntax variants (lines 49-60):

Variant Prefix Behavior
Non-exact text= Substring match
Exact text: or text:exact: Full string match
// Non-exact (substring) match
await ego.cdp('text=Sign in');

// Exact match
await ego.cdp('text:exact:Confirm');

The parseTextLocator helper creates appropriate matcher objects for each variant.

Attribute-Based Selectors: Label, Placeholder, Alt, Title, TestID

ego-browser provides dedicated selectors for common element attributes, all parsed similarly to text selectors:

Label Selectors

Lines 61-66 handle label: prefix for form element labels.

await ego.cdp('label:Password');

Placeholder Selectors

Lines 67-72 parse placeholder: for input hints.

await ego.cdp('placeholder:Search…');

Alt Selectors

Lines 73-78 handle alt: for image accessibility text.

await ego.cdp('alt:Logo');
await ego.cdp('alt:User avatar');

Title Selectors

Lines 79-84 parse title: for tooltip text.

await ego.cdp('title:Page Title');
await ego.cdp('title:Help');

Test-ID Selectors

Lines 85-90 handle testid: for data-testid attributes.

await ego.cdp('testid:submitBtn');
await ego.cdp('testid:nav-item');

Role Selectors: ARIA Accessibility Targets

Role selectors target elements by ARIA role with optional name filtering. Parsed at lines 101-108 with the role: prefix.

// Role only
await ego.cdp('role:button');

// Role with name constraint
await ego.cdp('role:button[name="Submit"]');

The parser extracts both role and optional name properties into the locator object.

Complete Code Reference: All Target Forms

// 1. CSS selector
await ego.cdp('.login-button');
await ego.cdp('loc=css:.my-class');

// 2. XPath expression
await ego.cdp('xpath=//a[contains(@href, "/settings")]');

// 3. Href exact match
await ego.cdp('href:/dashboard');

// 4. Text substring
await ego.cdp('text=Sign in');

// 5. Text exact match
await ego.cdp('text:exact:Confirm');

// 6. Label text
await ego.cdp('label:Password');

// 7. Placeholder text
await ego.cdp('placeholder:Search…');

// 8. Alt attribute
await ego.cdp('alt:User avatar');

// 9. Title attribute
await ego.cdp('title:Help');

// 10. Test ID
await ego.cdp('testid:nav-item');

// 11. ARIA role with name
await ego.cdp('role:button[name="Submit"]');

// 12. Internal scope query
await ego.cdp('internal:scope:{"base":"#parent","child":"button"}');

// 13. Internal filter query
await ego.cdp('internal:filter:{"base":"section","hasText":{"text":"Welcome"}}');

// With nth modifiers
await ego.cdp('internal:nth=2;css:#btn');
await ego.cdp('internal:last;xpath=//div');

How Resolution Works: From String to Element

According to the citrolabs/ego-lite source code, the resolution pipeline follows this sequence:

  1. parseLocator in src/element-resolver.ts parses the selector string into a locator object with a kind property
  2. The resolver functions (resolveElementCenter, resolveElementObjectId, etc.) dispatch based on kind
  3. Evaluation helpers in src/locator-query.ts (queryAllExpression, textElementsExpression, etc.) execute the appropriate DOM query in the browser context

Supported kind values: "query", "css", "xpath", "href", "text", "label", "placeholder", "alt", "title", "testid", "role".

Key Source Files

File Purpose
src/element-resolver.ts Contains parseLocator function that defines all 13+ target forms
src/locator-query.ts Provides browser-side evaluation expressions for each locator type

Summary

  • ego-browser recognizes 13+ element target forms for resolution, from simple CSS to complex internal queries
  • Core parser: parseLocator in src/element-resolver.ts handles all syntax recognition
  • Two advanced forms: internal:scope: and internal:filter: enable composable, conditional element resolution
  • Attribute selectors (label, placeholder, alt, title, testid) all follow consistent text-matching semantics
  • Role selectors support ARIA patterns with optional name constraints for accessibility-first automation
  • Nth modifiers (nth=N, last) work across all selector types for precise positional targeting

Frequently Asked Questions

What is the most reliable target form for flaky UIs?

Role selectors with explicit names (role:button[name="Submit"]) provide the most stability across DOM changes because they target accessibility semantics rather than implementation details. According to the ego-browser source in src/element-resolver.ts (lines 101-108), these map directly to ARIA properties that remain consistent even when CSS classes or DOM structure vary.

Can I combine multiple selector types in one target string?

Not directly—you must use internal scope or filter queries for composition. The internal:scope: and internal:filter: prefixes accept JSON objects that combine base selectors with child selectors or text constraints. See lines 31-33 in src/element-resolver.ts for the parser implementation.

Why does text=Search match differently than text:Search?

These trigger different parsing paths. text= (equals) creates a non-exact substring matcher, while text: (colon) routes through parseTextLocator which defaults to exact matching unless you specify text:exact:. This distinction exists at lines 49-60 of src/element-resolver.ts.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →