# How to Use getByRole, getByText, and getByLabel in ego-lite Locators

> Learn to use ego-lite locators getByRole, getByText, and getByLabel. Target elements with Playwright-style accessibility helpers and auto-waiting selectors for robust testing.

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

---

**Ego-lite exposes Playwright-style accessibility helpers through its `locator()` façade, enabling you to target elements by ARIA role, visible text, or associated labels using strictly-typed, auto-waiting selectors.**

The citrolabs/ego-lite library provides a lightweight runtime that mimics the Playwright API for browser automation. When working with **ego-lite locators**, you interact with a page object that returns a strict locator instance—one that automatically waits for elements and supports chaining accessibility-focused queries without requiring external browser drivers.

## How ego-lite Locators Expose Accessibility Helpers

Every page object in ego-lite provides a `locator()` method that returns a chainable locator instance. According to the source in [`src/helpers.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/helpers.ts), this object is generated by `createLocator()` and exposes the three core accessibility methods: `getByRole()`, `getByText()`, and `getByLabel()`. Each helper constructs a **scoped selector** string (prefixed with `loc=`) that the runtime resolves in the browser context.

The selector strings follow a strict grammar defined in [`src/helpers.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/helpers.ts) (lines 534–544):

- `loc=role:button[name="Submit"]`
- `loc=text:"Exact text"`
- `loc=label:"Email"`

These strings are parsed by the query engine in [`src/locator-query.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/locator-query.ts) and evaluated against the DOM or Accessibility tree.

## Querying Elements by ARIA Role with getByRole

The `getByRole(role, options?)` helper locates elements that expose a specific ARIA role—such as `button`, `link`, or `textbox`—and optionally filters by accessible name.

### Implementation in the Source Code

In [`src/helpers.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/helpers.ts), the method forwards to `roleSelector()`, which constructs the `loc=role:` selector. The heavy lifting occurs in [`src/locator-query.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/locator-query.ts) (lines 345–401), where a regex `^role:([A-Za-z0-9_-]+)(?:\[name=(.+)\])?$` extracts the role and name parameters. The engine then invokes `roleElementsExpression()` to build a DOM query that first checks an element’s explicit `role` attribute, falling back to implicit ARIA roles derived from the element type (e.g., `<button>` implicitly has role `button`).

```javascript
// Click a submit button by its ARIA role and accessible name
await page.locator('body')
          .getByRole('button', { name: 'Submit' })
          .click();

// Scope to a specific section before querying
await page.locator('section#settings')
          .getByRole('checkbox', { name: 'Enable notifications' })
          .check();

```

## Finding Visible Text with getByText

Use `getByText(text, options?)` to target elements whose visible or inner text matches a supplied string. By default, the matching is partial (`exact: false`).

### Text Matching Pipeline

Per the implementation in [`src/helpers.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/helpers.ts), this helper calls `textSelector("text", …)`, which generates a `loc=text:` query. The runtime resolves this via the generic text matcher in [`src/locator-query.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/locator-query.ts). When `exact: true` is passed, the selector enforces a literal match; otherwise, it accepts substrings.

```javascript
// Partial match (default behavior)
const saveBtn = page.locator('body').getByText('Save');
await expect(saveBtn).toBeVisible();

// Exact match
await page.locator('main')
          .getByText('Delete', { exact: true })
          .click();

```

## Targeting Form Controls via getByLabel

The `getByLabel(text, options?)` method targets form controls—such as inputs and selects—by their associated `<label>` element or `aria-label` attribute.

### Label Resolution Logic

This helper is implemented via `textSelector("label", …)` in [`src/helpers.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/helpers.ts), producing a `loc=label:` prefixed query. The resolution pipeline (referenced in [`src/element-resolver.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/element-resolver.ts), lines 251–317) maps this prefix to the text-matching engine but restricts the search to elements with label associations or explicit `aria-label` properties.

```javascript
// Fill an input field targeted by its label text
await page.locator('#login')
          .getByLabel('Email')
          .fill('alice@example.com');

```

## Selector Composition and Execution Flow

Understanding how ego-lite compiles these helpers into executable queries clarifies their behavior:

1. **Façade Creation**: Calling `page.locator(selector)` returns a locator object defined in [`src/helpers.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/helpers.ts).
2. **Scope Chaining**: Each helper invokes `scopedSelector()` to append the accessibility constraint to the base selector.
3. **Parsing**: [`src/locator-query.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/locator-query.ts) strips the `loc=` prefix and parses role or text parameters using dedicated regexes.
4. **Execution**: The generated expression—such as the role-matching logic in `roleElementsExpression()`—evaluates in the browser context, returning backend node IDs that the runtime wraps into a fresh locator for further actions like `click()` or `fill()`.

Because these helpers are pure JavaScript functions within the ego-lite runtime, they require **no additional configuration** or Playwright installation; simply import the `page` object from the global `ego` runtime and begin chaining.

## Summary

- ** ego-lite locators** provide Playwright-compatible accessibility methods through a strict, auto-waiting API.
- **`getByRole`** constructs `loc=role:` selectors parsed by [`src/locator-query.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/locator-query.ts) to match explicit or implicit ARIA roles.
- **`getByText`** leverages `textSelector("text", …)` in [`src/helpers.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/helpers.ts) to perform partial or exact visible-text matching.
- **`getByLabel`** uses `textSelector("label", …)` to resolve form controls by their label text or `aria-label`.
- All three helpers support chained scoping and return fresh locator instances for composable automation scripts.

## Frequently Asked Questions

### Does ego-lite require Playwright to be installed?

No. While the API mirrors Playwright's locator signatures—defined in [`src/format.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/format.ts) (lines 101–120) for documentation parity—ego-lite operates as a standalone runtime. The methods execute within the library's own browser context without external dependencies.

### How does `getByRole` handle implicit versus explicit ARIA roles?

The `roleElementsExpression()` function in [`src/locator-query.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/locator-query.ts) (lines 345–401) first inspects an element's explicit `role` attribute. If absent, it falls back to the implicit role derived from the HTML tag (for example, `<button>` maps to the `button` role), ensuring comprehensive accessibility coverage.

### Can I chain multiple ego-lite locators together?

Yes. Every call to `getByRole`, `getByText`, or `getByLabel` returns a new locator instance scoped to the previous selection. This allows you to narrow searches progressively, such as `page.locator('nav').getByRole('link', { name: 'Home' })`, which restricts the query to links within the navigation landmark only.

### What is the difference between exact and partial matching in `getByText`?

By default, `getByText` performs partial matching (`exact: false`), accepting any element containing the substring. Passing `{ exact: true }` constrains the selector to elements whose text content matches the string literally. This behavior is encoded in the `textSelector()` utility in [`src/helpers.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/helpers.ts) and reflected in the generated `loc=text:` query string.