Playwright·Cookbook Field Manual
Part 09 · Interaction Toolkit Card 45

Native Form Controls

Card 45: Native Form Controls

The portable agent skills for this pattern are playwright-interactions, playwright-locators and playwright-assertions.

What This Pattern Solves

Text inputs, checkboxes, radios, selects and buttons each carry state the browser already tracks: value, checked, selected, disabled, accessible description. You get flaky or wrong tests when you drive these controls with generic click() calls and read state back with getAttribute or innerText. Playwright has one action and one matcher for each control. Use them and the test reads like the form.

How It Works

  1. Text: fill() replaces the value in one input event. clear() empties it. pressSequentially() types key by key for widgets that listen to keys.
  2. Checkboxes and radios: check(), uncheck() and setChecked(bool) are idempotent and verify the result. Assert with toBeChecked().
  3. Selects: selectOption() takes a value, a { label }, or an array for multiple. Assert with toHaveValue() or toHaveValues().
  4. Pointer: hover() for CSS :hover content, dblclick(), and click({ button: 'right' }) for context menus.
  5. State: toBeDisabled() / toBeEnabled() instead of trying to click.
  6. Validation: toHaveAccessibleDescription() proves the error belongs to the field, and getByRole('alert') covers the form-level summary.

Code Example

await page.getByLabel('Accept terms').check();
await expect(page.getByLabel('Accept terms')).toBeChecked();

await page.getByLabel('Country').selectOption({ label: 'Canada' });
await expect(page.getByLabel('Country')).toHaveValue('ca');

await page.getByLabel('Toppings').selectOption(['cheese', 'olives']);
await expect(page.getByLabel('Toppings')).toHaveValues(['cheese', 'olives']);

// Bad: the text exists somewhere on the page, maybe next to the wrong field.
await expect(page.getByText('Enter a valid email')).toBeVisible();
// Good: a screen reader hears this error on this field.
await expect(page.getByLabel('Email')).toHaveAccessibleDescription('Enter a valid email');

Key Concepts

When to Use This Pattern

Isolated examples

Each control is built with page.setContent inside the spec. Run the tests to see each action paired with its matcher.

Run This Example

pnpm test src/45-native-form-controls