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:
parseLocatorinsrc/element-resolver.tsparses the selector string into a locator object with akindproperty- The resolver functions (
resolveElementCenter,resolveElementObjectId, etc.) dispatch based onkind - 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-browserrecognizes 13+ element target forms for resolution, from simple CSS to complex internal queries- Core parser:
parseLocatorinsrc/element-resolver.tshandles all syntax recognition - Two advanced forms:
internal:scope:andinternal: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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →