# Supported Selector Formats in ego-lite: CSS, XPath, Text, and loc= Syntax

> Discover ego-lite's powerful selector formats: CSS, XPath, text, loc= syntax, and more. Normalize your element selection for efficient testing and automation.

- Repository: [CitroLabs/ego-lite](https://github.com/citrolabs/ego-lite)
- Tags: api-reference
- Published: 2026-08-24

---

**ego-lite supports six distinct selector formats—raw CSS, prefixed XPath (`xpath=`), text matching (`text=`), compact `loc=` expressions (`css:`, `role:`, `href:`), and snapshot references (`@N`)—all normalized by the element-resolver before execution.**

The `citrolabs/ego-lite` repository provides a lightweight browser automation framework where agent commands rely on flexible string selectors to target DOM elements. Understanding the supported selector formats in ego-lite is critical for writing resilient automation scripts that handle dynamic web pages. These formats are parsed and validated by the **format** module, then resolved into executable queries by the **element-resolver** pipeline.

## Raw CSS Selectors

Raw CSS selectors require no prefix and accept any valid CSS3-compliant selector string. The resolver passes these directly to the browser's native query engine.

```javascript
// Select by ID and class combination
await click('#main .save-button');

// Select by attribute
await type('input[data-testid="email"]', 'user@example.com');

```

## XPath Selectors (xpath=)

XPath expressions provide complex DOM traversal capabilities and must be prefixed with `xpath=`. This format is parsed in [`src/element-resolver.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/element-resolver.ts) and converted to CDP runtime calls.

```javascript
// Select button by text content via XPath
await click('xpath=//button[text()="Submit"]');

// Select by partial attribute match
await waitFor('xpath=//input[contains(@class, "required")]');

```

## Text Matching (text=)

The `text=` prefix performs exact visible text matching, useful when semantic selectors are unavailable. The resolver normalizes whitespace during comparison.

```javascript
// Click link containing exact text
await click('text=Forgot Password');

// Wait for specific heading text
await waitFor('text=Dashboard Loaded');

```

## Compact loc= Syntax

The `loc=` prefix provides a unified DSL for specialized locator strategies, implemented in [`src/locator-query.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/locator-query.ts). This syntax supports three primary namespaces:

- **loc=css:** — Explicit CSS wrapper functionally identical to raw CSS selectors
- **loc=role:** — ARIA role selection with optional accessible name filtering via curly braces `{name}`
- **loc=href:** — Exact href attribute matching for anchor elements

```javascript
// loc=css: equivalent to raw CSS
await click('loc=css:.nav-item.active');

// loc=role: with name filter (role:button{Submit})
await click('loc=role:button{Save Changes}');

// loc=href: targeting specific paths
await click('loc=href:/account/settings');

```

## Snapshot References (@N)

Snapshot references allow agents to target elements captured in previous browser states. The parser recognizes numeric IDs prefixed with `@` or the explicit `@ref=` syntax.

```javascript
// Reference snapshot ID 42
await click('@42');

// Alternative explicit syntax
await waitFor('@ref=button42');

```

## Internal Parsing Architecture

The selector resolution pipeline involves four critical source files that demonstrate how raw strings transform into executable browser commands:

- **[`src/format.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/format.ts)** — Declares the public API contract and TypeScript interfaces that define accepted selector patterns
- **[`src/element-resolver.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/element-resolver.ts)** — Contains the core normalization logic that distinguishes between CSS, XPath, text, and `loc=` prefixes before routing to specific handlers
- **[`src/locator-query.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/locator-query.ts)** — Implements low-level conversion of `loc=` strings (role, href, css) into Chrome DevTools Protocol (CDP) runtime queries
- **[`src/helpers.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/helpers.ts)** — Provides utility functions that programmatically construct `loc=` strings for common patterns like `loc=role:button{name}`

## Practical Usage Examples

```javascript
// 1. Raw CSS - simplest form
await click('.primary-button');

// 2. XPath - complex structural queries
await type('xpath=//form[@id="login"]//input[@type="password"]', 'secret');

// 3. Text matching - semantic-free pages
await click('text=Accept Cookies');

// 4. loc=role - accessibility-first selection
await click('loc=role:checkbox{Subscribe to newsletter}');

// 5. loc=href - link verification
await click('loc=href:https://example.com/privacy');

// 6. Snapshot reference - stateful navigation
await click('@15');

```

## Summary

- **Raw CSS selectors** require no prefix and pass directly to the browser's query engine
- **XPath selectors** use the `xpath=` prefix for complex DOM traversal expressions
- **Text selectors** use the `text=` prefix for exact visible text matching
- **loc= syntax** provides compact wrappers for CSS (`loc=css:`), ARIA roles (`loc=role:{name}`), and href attributes (`loc=href:`)
- **Snapshot references** use `@N` or `@ref=` syntax to target previously captured elements
- The **element-resolver** and **format** modules handle normalization, while **locator-query.ts** generates CDP commands

## Frequently Asked Questions

### What is the difference between raw CSS and loc=css: selectors?

Both target elements using CSS syntax, but `loc=css:` explicitly routes through the locator pipeline in [`src/locator-query.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/locator-query.ts). Raw CSS selectors are passed directly to `document.querySelector`, while `loc=css:` strings undergo additional preprocessing and validation, making them preferred when building selectors programmatically via [`src/helpers.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/helpers.ts).

### How do I select an element by its accessible role in ego-lite?

Use the `loc=role:` prefix followed by the ARIA role and optional name in curly braces. For example, `loc=role:button{Submit}` selects a button with the accessible name "Submit". This is processed by the role resolver in [`src/locator-query.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/locator-query.ts) which queries the browser's accessibility tree.

### Can I combine multiple selector types in a single query?

No, ego-lite expects a single selector string per operation. To implement complex logic (e.g., "find element matching CSS or text"), execute multiple locator calls or use XPath which supports boolean logic via `|` operators or complex predicates within the `xpath=` string.

### What happens if a snapshot reference like @42 points to a stale element?

If the referenced element no longer exists in the current DOM, the element-resolver in [`src/element-resolver.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/element-resolver.ts) will return a "not found" error, typically throwing an exception that your agent code should catch. Snapshot references are bound to specific browser states and do not auto-update when the page changes.