How the `loc=` Locator Syntax Works in ego‑lite

The loc= prefix in ego‑lite activates a structured locator parser in src/locator‑query.ts that routes selectors to specialized handlers for XPath, CSS, text matching, attributes, and ARIA roles, falling back to plain CSS selectors when no specific prefix matches.

ego‑lite provides agents with a unified string syntax to locate page elements. When a selector begins with loc=, the library treats the remainder as a structured locator and parses it in src/locator‑query.ts to generate efficient DOM‑query expressions. This architecture enables expressive, high‑level selectors—such as targeting by ARIA role or link href—while maintaining compatibility with standard CSS.

Core Parsing Flow in locator‑query.ts

All loc= processing originates in src/locator‑query.ts, specifically within the queryAllExpression function. The parser implements a cascading dispatch mechanism that examines the selector string and constructs the appropriate JavaScript expression for browser evaluation.

Normalization and Strategy Dispatch

The parser first strips the loc= prefix to reveal the underlying strategy:

const normalized = raw.startsWith("loc=") ? raw.slice(4) : raw;

After normalization, the code checks for specific locator prefixes. If none match, the raw string is treated as a plain CSS selector and passed to querySelectorAll.

Supported Locator Types

The implementation recognizes eight distinct locator categories according to the source logic:

  • XPath – Strings starting with xpath= trigger document.evaluate for complex DOM traversal.
  • CSS – The css: prefix delegates directly to querySelectorAll.
  • Href – The href: prefix targets <a> elements matching a specific path or full URL.
  • Text – The text: prefix (or legacy text=) matches visible text content with optional exact‑match modifiers.
  • Attributes – Prefixes label:, placeholder:, alt:, title:, and testid: filter elements by case‑insensitive attribute values.
  • ARIA Role – The role: prefix accepts syntax like role:button[name=…] to select elements by explicit or implicit ARIA role, optionally filtering by accessible name.

The queryAllExpression Builder

The queryAllExpression function constructs the actual JavaScript snippet executed in the browser context. Each branch returns a specialized expression:

if (raw.startsWith("xpath=")) { /* build XPath expression */ }
if (normalized.startsWith("css:")) { /* standard querySelectorAll */ }
if (normalized.startsWith("href:")) { /* anchor href matcher */ }
if (normalized.startsWith("text:")) { /* text content matcher */ }
// ... role parsing via parseRoleLocator()
return querySelectorAllExpression(rootExpression, raw);

This approach keeps the browser‑side execution lightweight while allowing the host to compose complex queries.

Integration with the Resolution Pipeline

The locator system spans three key files in the repository:

  • src/locator‑query.ts – Parses loc= strings and builds query expressions.
  • src/element‑resolver.ts – Consumes queryAllExpression output and resolves selectors to concrete element references.
  • src/driver/locator.ts – Exposes public helpers like click and type that forward selector strings through the resolver.

This architecture ensures that all public driver methods accept the same unified string format.

Practical Code Examples

The following patterns demonstrate how agents use loc= in production code:

Target a button via CSS:

await click('loc=css:#submit-button');

Select a link by exact URL path:

await click('loc=href:/dashboard');

Type into a field using placeholder text:

await type('loc=placeholder:"Search items"', 'laptop');

Click a checkbox by label with exact matching:

await click('loc=label:exact:"Accept terms"');

Interact via ARIA role and accessible name:

await click('loc=role:button[name:/Submit/i]');

Fallback to raw CSS when omitting loc=:

await click('#logout');  // Treated as plain CSS selector

Combine CSS with text filtering:

await click('loc=css:.menu-item:has-text("Settings")');

Summary

  • Explicit syntax – The loc= prefix signals structured parsing in src/locator‑query.ts, distinguishing high‑level locators from arbitrary JavaScript.
  • Multi‑strategy support – Supports XPath, CSS, href, text, attributes (label, placeholder, alt, title, testid), and ARIA role selection.
  • Graceful fallback – Unrecognized strings default to standard CSS selection via querySelectorAll.
  • Consistent API – All driver methods (click, type, waitFor) leverage the same resolution pipeline through element‑resolver.ts.

Frequently Asked Questions

What happens if I omit the loc= prefix in ego‑lite?

When the loc= prefix is absent, the selector bypasses the structured parser in src/locator‑query.ts and is treated as a raw CSS selector passed directly to querySelectorAll. This provides backward compatibility for simple element targeting.

How does ego‑lite handle ARIA role selectors with accessible names?

The parser extracts the role and optional name from strings like loc=role:button[name=/Submit/i]. It uses the parseRoleLocator() helper to generate an expression that matches elements by their computed ARIA role and filters by the provided accessible name pattern.

Can I use XPath expressions with the loc= syntax?

Yes. Prefix your selector with loc=xpath= to trigger the XPath branch in queryAllExpression, which builds a document.evaluate call for complex DOM queries that CSS cannot express.

Where is the loc= parsing logic implemented?

All parsing logic resides in src/locator‑query.ts within the queryAllExpression function. This module constructs JavaScript expressions that src/element‑resolver.ts executes in the browser context to resolve elements.

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 →