Ego-Browser Element Resolver Selector Forms: Complete Guide to 7 Locator Types

Ego-browser's element resolver supports seven distinct selector forms including reference IDs (@N), CSS locators (loc=css:), ARIA role locators (loc=role:), href locators (loc=href:), XPath expressions (xpath=), raw CSS selectors, and text locators (loc=text:).

The element resolver is the core translation layer in citrolabs/ego-lite that converts high-level selector strings into concrete DOM references for browser automation agents. Understanding these ego-browser element resolver selector forms is essential for writing reliable automation scripts.

Reference Selector Form (@N)

The reference form uses a snapshot reference ID to fetch elements directly from the most recent snapshot map.

This is the fastest resolution method because it bypasses DOM querying entirely. The numeric ID corresponds to the backendNodeId captured during page snapshots.

// Click element with reference ID 15 from the latest snapshot
await click('@15')

// Reference IDs persist across navigation within the same session
await click('@42')

Reference selectors are defined in src/element-resolver.ts where the resolver checks for the @ prefix before delegating to snapshot-based lookup routines.

CSS Locator Form (loc=css:)

The CSS locator form executes standard CSS selectors against the page DOM using querySelectorAll.

// Explicit CSS locator with prefix
await click('loc=css:button.primary')

// Target nested elements
await click('loc=css:nav ul li:first-child')

// Combine with pseudo-selectors
await click('loc=css:input:focus')

The resolver strips the loc=css: prefix and passes the remaining string to the browser's native CSS selector engine. This form supports the full CSS selector specification.

Raw CSS Form (No Prefix)

Bare CSS selectors without any prefix are treated as CSS locators for backward compatibility.

// Implicit CSS selector - identical behavior to loc=css:
await click('.nav-item.active')

// Complex nested selector
await click('div.article > p.intro')

// Attribute selectors work unchanged
await click('[data-testid="submit"]')

This legacy form exists in src/element-resolver.ts as a fallback when no recognized prefix is detected. The resolver applies the same querySelectorAll execution path as explicit CSS locators.

ARIA Role Locator Form (loc=role:)

The ARIA role locator form queries the browser's Accessibility Tree to find elements by their semantic role.

// Find first button role in accessibility tree
await click('loc=role:button')

// Target navigation landmark
await click('loc=role:navigation')

// Interactive elements
await click('loc=role:link')
await click('loc=role:textbox')

This form is particularly valuable for accessibility-first automation and resilient scripts that survive DOM restructuring. The resolver interfaces with Chrome DevTools Protocol accessibility domains in src/element-resolver.ts.

Href Locator Form (loc=href:)

The href locator form targets anchor (<a>) elements by matching their href attribute values.

// Exact URL match
await click('loc=href:https://example.com/login')

// Partial path matching
await click('loc=href:/dashboard')

// Query string inclusion
await click('loc=href:?tab=settings')

The resolver performs substring matching against the full href attribute, making partial matches practical for dynamic URLs. This form is implemented alongside other prefixed locators in the main resolver logic.

XPath Locator Form (xpath=)

The XPath form evaluates full XPath 1.0 expressions against the document.

// Element by tag and attribute
await click('xpath=//div[@class="content"]')

// Text-based selection
await click('xpath=//button[text()="Continue"]')

// Complex predicates
await click('xpath=//input[@type="email" and @required]')

The resolver passes XPath expressions to the browser's native XPath engine. Error handling distinguishes between malformed expressions (permanent errors) and valid expressions returning no matches (transient errors).

Text Locator Form (loc=text:)

The text locator form (available in later versions) finds elements by their visible text content.

// Exact text match
await click('loc=text:Sign In')

// Case-sensitive matching
await click('loc=text:Logout')

// Multi-word strings
await click('loc=text:Add to Cart')

Text resolution performs exact string matching against rendered text nodes. This form requires the most careful handling of whitespace and capitalization.

Error Classification in Element Resolution

The resolver throws ElementResolutionError instances defined in src/errors.ts. These errors carry a transient/permanent classification:

  • Transient errors: DOM not ready, element temporarily detached — trigger retry loops
  • Permanent errors: Invalid selector syntax, unsupported form — fail immediately

This classification enables higher-level wait logic in src/helpers.ts functions like click() and type() to implement intelligent retry strategies.

Selector Form Resolution Pipeline

The complete resolution flow in src/element-resolver.ts follows this precedence:

  1. Check for @ prefix → reference lookup
  2. Check for loc=css: prefix → explicit CSS query
  3. Check for loc=role: prefix → accessibility tree query
  4. Check for loc=href: prefix → anchor href matching
  5. Check for loc=text: prefix → visible text search
  6. Check for xpath= prefix → XPath evaluation
  7. No prefix detected → implicit CSS query

Each branch delegates to specialized resolvers or browser protocol methods, then returns normalized element references to src/element-ops.ts for interaction.

Summary

  • Reference selectors (@N) offer fastest resolution via snapshot IDs
  • CSS locators support both explicit (loc=css:) and implicit (raw) forms
  • ARIA role locators query the accessibility tree for semantic matching
  • Href locators target links by URL pattern matching
  • XPath locators enable complex document traversal expressions
  • Text locators find elements by exact visible text content
  • Error classification in src/errors.ts distinguishes retryable from fatal failures

Frequently Asked Questions

How does ego-browser choose which selector form to use?

The resolver examines the selector string for recognized prefixes in fixed precedence order. Prefixes like @, loc=, and xpath= trigger specific resolution branches, while unprefixed strings default to CSS selection. This logic is centralized in src/element-resolver.ts.

When should I use reference selectors versus CSS locators?

Use reference selectors (@N) for maximum speed when element stability is guaranteed. Use CSS locators when elements may move in the DOM or when scripting across multiple page states where snapshot IDs become invalid.

What happens if a selector matches multiple elements?

The resolver returns the first matching element for all selector forms except where explicitly noted. For CSS and XPath forms, this corresponds to querySelectorAll()[0] behavior. Use more specific selectors or XPath predicates to target precise elements.

Are text locators available in all ego-browser versions?

The loc=text: form was added in later versions. Check your package/ego-browser version against the repository changelog. Earlier versions throw ElementResolutionError with permanent classification for unrecognized prefix types.

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 →