The problem
You have a checkbox in the DOM, for example, with id="AcceptedTermsOfUse"
, that is outside of the visible area of the page (viewport), for example with very large negative x
coordinates like x = -9459
.
When you try to run:
await page.locator('#AcceptedTermsOfUse').click();
Playwright throws an error like:
Error: locator.click: Test timeout ...
“element is outside of the viewport”
or
"Call log:
- waiting for locator('input[type="checkbox"][name="AcceptedTermsOfUse"]')
- locator resolved to "
This means: the element exists, it is “visible” in terms of CSS (not display:none
, not visibility:hidden
), but it is not in a position where a user could physically click it, because it’s positioned or hidden off‑screen.
Why this happens
Common causes:
Off‑screen styling
The input is styled with position: absolute
(or similar), using left: -xxxxx
or transform
that pushes it outside the viewport.
Styled label + hidden input
Many UI frameworks hide the real off-screen and use only a label plus pseudo-elements (::before, ::after) to render the visible checkbox square. This allows them to style a “fancy checkbox” without relying on the browser’s native styling. The user clicks on the label, which propagates the click to the hidden input. So the input is technically visible (not display:none), but positioned outside the viewport
so the user never interacts with it directly.
Playwright actionability checks
Before performing locator.click()
, Playwright ensures:
- the element is visible
- enabled
- stable (not moving/animating)
- within the viewport or can be scrolled into it
If any of these fail, Playwright won’t click.
Known tricky cases
Sometimes elements are technically visible but still unreachable due to layout/CSS. This is common with checkboxes hidden for custom styling.
Real example
In this case, the checkbox was:
- Visible in CSS terms
- Enabled
- But with
boundingBox().x = -9459
— far to the left - Absolutely positioned
- No scrollable parent to bring it into view
So Playwright couldn’t click because it wasn’t physically actionable.
Possible solution
1. Use page.evaluate
with element.click()
await page.evaluate(() => {
const checkbox = document.getElementById("AcceptedTermsOfUse");
if (checkbox) checkbox.click();
});
This works even if the input is off‑screen, because it fires a DOM click programmatically.
2. Manually set checked
and dispatch events
await page.evaluate(() => {
const checkbox = document.getElementById("AcceptedTermsOfUse") as HTMLInputElement;
if (checkbox) {
checkbox.checked = true;
checkbox.dispatchEvent(new Event('change', { bubbles: true }));
}
});
Forces the state and triggers a change
event.
Investigation
You can investigate this behavior directly in the browser console. For example, open DevTools and run:
document.getElementById("AcceptedTermsOfUse").click();
You’ll notice the checkbox gets checked and any attached event listeners fire — even if the element is off-screen.
Why document.getElementById("AcceptedTermsOfUse").click()
works off-screen, but Playwright’s locator.click()
does not?
When you call element.click()
in the browser (either in the console or inside page.evaluate()
), the browser’s DOM engine executes HTMLElement.prototype.click()
.
This method programmatically triggers all associated events (mousedown
, mouseup
, click
, input
, change
, depending on the element) and updates the element state. Importantly:
- The browser does not require the element to be inside the viewport.
- The DOM allows simulating a click even if the element is positioned off-screen.
Why Playwright behaves differently
Playwright aims to simulate real user interaction, not just fire DOM events. When you call:
await page.locator('#AcceptedTermsOfUse').click();
Playwright performs actionability checks:
- The element must be visible, enabled, stable (not moving), and not covered by other elements.
- The element must be within the viewport, or Playwright will attempt to scroll it into view.
- If Playwright cannot make the element actionable, it throws:
"element is outside of the viewport"
.
These checks exist so tests mimic how a real user would interact with the page — for example, preventing clicks through invisible or off-screen elements.
Top comments (0)