# How to Use Pointer Actions in ego-lite: click, doubleClick, hover, drag, and wheel

> Master ego-lite pointer actions: click, doubleClick, hover, drag, and wheel. Easily control mouse events in your tests using page.mouse or locator methods for efficient web automation.

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

---

**Invoke pointer actions in ego-lite through the `page.mouse.*` facade, `locator.*` methods, or direct top-level helpers—each backed by the same Playwright-style driver in [`src/driver/pointer.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/driver/pointer.ts).**

The `ego-lite` browser automation toolkit provides a unified pointer API for driving mouse interactions inside the `ego` runtime. Whether you need to click a button, drag across a canvas, or scroll a viewport, the library resolves targets automatically and dispatches CDP-native mouse events. All pointer helpers are re-exported from [`src/helpers.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/helpers.ts) and injected into the agent script scope by `helperContext()` at `helpers.ts:L22`.

## Three Access Patterns for Pointer Actions

Every pointer method is available through three interchangeable entry points:

- **Page facade** – `await page.mouse.click('button#ok')`. This delegates to `pointer.click` inside [`src/driver/pointer.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/driver/pointer.ts).
- **Locator facade** – `await page.locator('button#ok').click()`. Locator methods call the same underlying driver after auto-waiting for the element, as wired in `src/helpers.ts:L60`.
- **Direct helper** – `await click('button#ok')`. Functions such as `click`, `dblclick`, `hover`, `drag`, and `wheel` are exported directly from `src/helpers.ts:L30` and callable in any agent script.

## How MouseTarget Resolution Works

Before any mouse event fires, the driver normalizes your target through the **`MouseTarget`** type defined at `src/driver/pointer.ts:L13`. The internal `resolveMouseTarget` routine at `pointer.ts:L302` accepts:

- A **CSS selector** or **@ref** string, which resolves to the element’s centre via `elementCenter` in [`src/driver/observe.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/driver/observe.ts).
- **Viewport coordinates** as `[x, y]` or `{x, y}`.
- A **selector-plus-offset** object such as `{ selector: 'div', x: 10, y: 5 }`, which computes the element’s top-left plus the given offset.

If a selector is provided, the helper waits for visibility ([`src/driver/waits.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/driver/waits.ts)), calls `scrollIntoViewIfNeeded` at `pointer.ts:L59`, and then queries the final coordinates. Invalid targets raise a clear `Error` from `resolveMouseTarget` at `pointer.ts:L41`.

## Available Pointer Methods

### click(target, options?)

The `click` implementation at `src/driver/pointer.ts:L63` resolves the target, moves the pointer, and dispatches a full click sequence. Its signature accepts `target: MouseTarget` and an optional `options` object with keys for `button`, `clickCount`, `label`, and `timeout`. When `label` is supplied, the runtime invokes `ego.animationHighlightMouseToPosition` via the `maybeHighlight` path at `pointer.ts:L66`.

### dblclick(target, options?)

Double-clicking is handled at `src/driver/pointer.ts:L99`. The helper forces `clickCount: 2` and delegates to the same `click` routine, producing two rapid button presses without duplicate target-resolution logic.

### hover(target, options?)

Use `hover` at `src/driver/pointer.ts:L16` to move the cursor over an element without pressing any buttons. It accepts the same `MouseTarget` and optional `label` or `timeout` values.

### drag(points, options?)

The `drag` method at `src/driver/pointer.ts:L38` performs a press-and-move sequence. Supply an array of at least two `MouseTarget` points; the driver presses the configured button on the first point, moves through each intermediate coordinate, and releases the button at the final point.

### wheel(deltaX?, deltaY?, options?)

Scrolling is driven by `wheel` at `src/driver/pointer.ts:L81`. The default `deltaY` is `300`, where positive values scroll down. When the page is visible and focused, it sends a CDP `mouseWheel` event; otherwise it falls back to a synthetic `WheelEvent`. You can pass `deltaX` for horizontal scrolling.

### scrollIntoViewIfNeeded(selector)

At `src/driver/pointer.ts:L59`, this helper calls the element’s native `scrollIntoViewIfNeeded` (or `scrollIntoView`) to guarantee visibility before a subsequent click or hover. It is invoked automatically when you use a string selector with the other pointer methods.

## Practical Code Examples

```js
// 1. Click a button with a debug label
await click('button#submit', { label: 'Submit button' });

// 2. Double-click viewport coordinates on a canvas
await dblclick([150, 200]);

// 3. Hover over an element located by @ref
await hover('@42');

// 4. Drag from one selector to an offset of another
await drag(
  ['div.start', { selector: 'div.end', x: 10, y: 5 }],
  { label: 'Drag start → end' }
);

// 5. Scroll down 400 px at the viewport centre
await wheel(0, 400, { x: 400, y: 300 });

// 6. Use the page.mouse facade
await page.mouse.click('a.next');
await page.mouse.hover([500, 250]);
await page.mouse.wheel(0, -200); // scroll up
await page.mouse.drag([[100, 100], [200, 200]]);

// 7. Use a locator for auto-wait and auto-highlight
await page.locator('input[name="search"]').fill('ego-lite');
await page.locator('button.search').click();

```

These examples run inside an `ego` agent script where `helperContext()` injects the direct helpers into the global scope.

## Summary

- **ego-lite pointer actions** are unified under a single Playwright-style driver in [`src/driver/pointer.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/driver/pointer.ts).
- You can reach them via `page.mouse.*`, `locator.*`, or direct top-level helpers exported from [`src/helpers.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/helpers.ts).
- The flexible `MouseTarget` type supports selectors, coordinates, and selector-plus-offset objects, resolved by `resolveMouseTarget` at `pointer.ts:L302`.
- `click`, `dblclick`, `hover`, `drag`, `wheel`, and `scrollIntoViewIfNeeded` cover the full range of mouse and scroll interactions.
- Supply a `label` option to trigger visual highlight animations during debugging.

## Frequently Asked Questions

### What is the difference between `click()` and `page.mouse.click()`?

There is no behavioral difference—both invoke the same `pointer.click` routine at `src/driver/pointer.ts:L63`. The direct `click()` helper is simply a convenience export from `src/helpers.ts:L30` that avoids chaining through the page object, while `page.mouse.click()` matches the Playwright API surface.

### Can I scroll an element into view before clicking?

Yes. When you pass a selector to any pointer method, the driver automatically calls `scrollIntoViewIfNeeded` at `src/driver/pointer.ts:L59` after waiting for the element to become visible. You can also invoke it manually if you need precise control over the scroll timing.

### How do I perform a drag operation between arbitrary coordinates?

Use the `drag` helper with an array of coordinate targets. Provide at least two points; the driver presses the mouse button at the first point and releases it at the last, moving through any intermediate targets. For example, `await drag([[100, 100], [200, 200]])` performs a straight-line drag inside the viewport.

### Does ego-lite provide `scroll` or `scrollBy` helpers?

The library exposes `wheel(deltaX, deltaY)` at `src/driver/pointer.ts:L81` as its primary scroll mechanism. It dispatches a CDP `mouseWheel` event when the page is focused, otherwise it injects a synthetic `WheelEvent`. Positive `deltaY` scrolls downward, and negative values scroll upward, giving you the same control as native `scrollBy` without a separate named helper.