Skip to content

Getting Started ​

Welcome to Acquiescence! This guide will help you understand the basics and get up and running quickly.

What is Acquiescence? ​

Acquiescence is a TypeScript library that provides sophisticated element state querying and interaction readiness detection for web applications. It goes far beyond simple existence checks to determine if elements are truly ready for user interaction.

Core Features ​

Element State Queries ​

Check various states of DOM elements:

  • Visibility: Is the element visible on the page?
  • Enabled/Disabled: Can the element be interacted with?
  • Editable: Can the element accept text input?
  • Checked: Is a checkbox, radio button, or element with a role allowing aria-checked checked, unchecked, or indeterminate?
  • In Viewport: Is the element currently visible in the viewport?
  • Stable: Has the element stopped moving/animating?

Interaction Readiness ​

Determine if an element is ready for specific interactions:

  • Click, double-click, hover
  • Type, clear input
  • Drag and drop operations
  • Screenshot capture

Smart Waiting ​

Wait for elements to become ready with:

  • Automatic scrolling into view
  • Stability detection (waits for animations to complete)
  • Configurable timeouts and polling intervals
  • Precise hit point calculation

Text, Labels, and ARIA States ​

Find and check elements as a user would name them:

  • Check which elements contain a text
  • Find elements by their labels, and get an element's labels
  • Match elements against ARIA states such as checked, pressed, or expanded
  • Find the open shadow roots to include in a search

Accessibility Snapshots ​

Describe a page as assistive technology sees it, in a format compatible with Playwright's aria snapshots, and match it against templates. See Accessibility Snapshots.

DOM Snapshots ​

Record a document, with the state of its inputs, scroll positions, and shadow roots, in the format of the snapshots in Playwright's traces. See DOM Snapshots.

Element Descriptions ​

Describe the element a user acts on by the facts a tool can name it by: role, accessible name, labels, attributes, text, and a CSS path. See Element Descriptions.

Action Recording ​

Record the clicks, typing, key presses, choices, and files of a user's real input as actions. See Action Recording.

Element Picking ​

Let a user pick an element with the mouse: the element under the pointer is highlighted, and the one clicked is reported without the page seeing the click. See Element Picking.

Basic Usage ​

1. Import the Library ​

typescript
import { ElementStateInspector } from 'acquiescence';

2. Create an Inspector Instance ​

typescript
const inspector = new ElementStateInspector();

TIP

You can reuse a single ElementStateInspector instance throughout your application. The inspector caches computed styles for performance. The caches live as long as the inspector, and hold elements weakly, so removed elements can still be garbage collected.

3. Query Element States ​

Check a Single State ​

typescript
const button = document.querySelector('button');
const result = await inspector.queryElementState(button, 'visible');

console.log(result.matches); // true or false
console.log(result.received); // 'visible' or 'hidden'

Check Multiple States ​

typescript
const input = document.querySelector('input');
const result = await inspector.queryElementStates(
  input, 
  ['visible', 'enabled', 'editable']
);

if (result.status === 'success') {
  console.log('Input is ready for typing!');
} else if (result.status === 'failure') {
  console.log(`Input is not ready: ${result.missingState}`);
} else if (result.status === 'error') {
  console.log(`Error: ${result.message}`);
}

4. Check Interaction Readiness ​

typescript
const button = document.querySelector('button');
const result = await inspector.isInteractionReady(button, 'click');

if (result.status === 'ready') {
  console.log('Ready to click at:', result.interactionPoint);
} else if (result.status === 'needsscroll') {
  console.log('Element needs to be scrolled into view');
} else {
  console.log('Element is not ready for interaction');
}

5. Wait for Interaction Readiness ​

typescript
const button = document.querySelector('button');

try {
  const hitPoint = await inspector.waitForInteractionReady(
    button,
    'click',
    5000 // 5 second timeout
  );
  
  console.log(`Ready to click at (${hitPoint.x}, ${hitPoint.y})`);
  // Perform your click action here
} catch (error) {
  console.error('Element not ready within timeout:', error.message);
}

Automatic Scrolling

waitForInteractionReady() automatically scrolls elements into view if they're not currently visible in the viewport.

Common Patterns ​

Pattern 1: Verify Before Action ​

Always verify an element's state before performing actions:

typescript
const submitButton = document.querySelector('#submit');
const result = await inspector.queryElementStates(
  submitButton,
  ['visible', 'enabled', 'stable']
);

if (result.status === 'success') {
  submitButton.click();
} else {
  console.warn('Cannot click button:', result);
}

Pattern 2: Wait with Timeout ​

Use timeouts to avoid waiting indefinitely:

typescript
async function clickWhenReady(element: Element, timeout: number = 5000) {
  try {
    await inspector.waitForInteractionReady(element, 'click', timeout);
    element.dispatchEvent(new MouseEvent('click'));
  } catch (error) {
    throw new Error(`Element not ready after ${timeout}ms`);
  }
}

Pattern 3: Check Visibility Helpers ​

For simple checks, use the helper methods:

typescript
const element = document.querySelector('.my-element');

if (inspector.isElementVisible(element)) {
  console.log('Element is visible');
}

if (inspector.isElementDisabled(element)) {
  console.log('Element is disabled');
}

const readOnly = inspector.isElementReadOnly(element);
if (readOnly === true) {
  console.log('Element is read-only');
} else if (readOnly === false) {
  console.log('Element is editable');
} else {
  console.log('Element is not an input/editable element');
}

Element States Reference ​

StateDescription
visibleElement is visible (has positive size, not hidden by CSS)
hiddenElement is not visible
enabledElement is not disabled
disabledElement is disabled (via disabled attribute or aria-disabled)
editableElement can accept text input (not disabled or readonly)
checkedCheckbox, radio button, or element with a role allowing aria-checked is checked
uncheckedSuch an element is not checked
indeterminateSuch an element is in a mixed state
inviewElement is currently visible in the viewport
notinviewElement is not in viewport but could be scrolled into view
unviewableElement cannot be scrolled into view (hidden by overflow)
stableElement's position hasn't changed for at least one animation frame

Next Steps ​

Released under the Apache License 2.0.