Read element attributes in Playwright

Read current HTML attributes with getAttribute(), assert them with toHaveAttribute(), and distinguish missing attributes from empty values.

Best practices
Illustration of software development and testing

Use await locator.getAttribute('data-action') to read an attribute as a string or null. To verify it in a test, prefer await expect(locator).toHaveAttribute('data-action', 'cancel'), which retries. A missing attribute returns null; an existing attribute with an empty value returns ''.

The snippets assume Playwright Test's expect is imported and the page is loaded. Each locator used for a single-element operation must identify one element; add a name or another constraint if your page has several links or buttons.

Read and assert attributes

const href = await page.getByRole('link', { name: 'Docs' }).getAttribute('href');
const action = await page.getByRole('button', { name: 'Cancel' }).getAttribute('data-action');

await expect(page.getByRole('button', { name: 'Cancel' }))
  .toHaveAttribute('data-action', 'cancel');
await expect(page.getByRole('link', { name: 'Docs' }))
  .toHaveAttribute('href', /\/docs/);

Check classes and boolean attributes

// Match a complete class token without comparing the entire class string.
await expect(locator).toHaveClass(/(^|\s)active(\s|$)/);

// Effective disabled state versus literal attribute presence.
const isDisabled = await locator.isDisabled();
const hasAttr = (await locator.getAttribute('disabled')) !== null;

The semantic method is normally better when you care whether a control is disabled. Attribute presence and effective state can differ, for example when a disabled ancestor fieldset affects a control.

Distinguish null from an empty string

Given:

<div data-empty="" data-none></div>
  • getAttribute('data-empty') returns ''.
  • getAttribute('data-none') also returns ''.
  • getAttribute('data-missing') returns null.

Use !== null to test presence. A truthiness check incorrectly treats an existing empty attribute as absent.

Attributes and DOM properties

getAttribute() reads the current HTML attribute. Scripts can update attributes, so they are not permanently frozen at their initial markup values. A form control's live state, such as value or checked, is represented by DOM properties that can diverge from the attributes:

await locator.inputValue();          // Current form-control value.
await locator.getAttribute('value'); // Current value attribute, not necessarily the live input.

Frequently asked questions

Why does getAttribute() return an old value or null?

You may need a DOM property or semantic state instead. Use inputValue() for a control's current value, isChecked() for its checked state, or isVisible() for Playwright's visibility query.

Can I read data attributes?

Yes: getAttribute('data-user-id') reads that attribute directly. For a test locator, getByTestId('submit-btn') uses data-testid by default; the attribute name is configurable.

How do I assert that an attribute is absent?

Use await expect(locator).not.toHaveAttribute('disabled', /.*/) for a retrying check. Reading the attribute and then applying toBeNull() only checks one snapshot. If the requirement is that the control is enabled, use toBeEnabled() instead; attribute absence is not a general guarantee of actionability.

References

Related reading

Get a tailored plan

Contact us

Join the community

Scan with WeChat
to join the community

Try Guance

Start online and pay only for what you use.

Get started

Choose a Guance plan

Code hosting