DriversRecommendedOutdated drivers can make a good PC feel brokenScan driver issues before chasing fixes manually.Scan NowOctober DealsAmazon USOctober deal check: compare before you payAmazon US: current deals, useful picks and tech finds.Check DealsWindows FixRecommendedWindows errors stealing your time? Find the fix fastScan stability, cleanup and performance issues.Fix Now×
Skip to content
World desk7 min

How to Screenshot a Scrollable Element with Playwright (Without Missing Its Hidden Content)

A practical Playwright guide to screenshotting scrollable elements: capture the visible viewport, position internal scrolling precisely, handle lazy lists and animation, and capture multiple segments when full stitching is required.
Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Use a locator for the scrollable element and call locator.screenshot(). Playwright captures the element’s visible bounds at its current internal scroll position; it does not automatically stitch every pixel in a long, scrollable container. Set scrollTop, scroll with the mouse, wait for lazy content, and then capture each position you need.

This distinction matters because page.screenshot({ fullPage: true }) captures the full scrollable page, not the complete internal scroll range of a nested panel. The official guidance is documented in Playwright’s screenshots guide and the Locator API reference.

Capture the visible portion of a scrollable element

Start with a locator, position the container, and call its screenshot method:

import { test } from '@playwright/test';

test('capture a scrolling panel', async ({ page }) => {
  await page.goto('https://example.com/dashboard');

  const panel = page.getByTestId('scrolling-container');
  await panel.waitFor();

  await panel.screenshot({ path: 'panel.png' });
});

The resulting image is clipped to the locator’s rendered bounds. If the element is a scrollable container, only the content currently visible through that container appears. A locator screenshot is therefore the correct API for “what the user can see in this panel right now,” not for a one-call, stitched image of the panel’s entire internal scroll range.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Prefer a stable role, test ID, or accessible label over a brittle CSS chain. For example:

const panel = page.getByRole('region', { name: 'Activity feed' });
// or: page.getByTestId('activity-feed');
await panel.screenshot({ path: 'activity-visible.png' });

Choose the capture scope first

Goal API What it captures
Visible part of one element locator.screenshot() The element’s box at its current scroll position
Entire page, including page-level scrolling page.screenshot({ fullPage: true }) A full scrollable page rendered as one tall screenshot
Specific internal section locator.evaluate() plus locator.screenshot() The section after you set its internal offset

Playwright describes a full-page screenshot as a full scrollable page “as if you had a very tall screen and the page could fit it entirely.” That option changes page capture scope; it does not make a locator screenshot traverse a nested element’s hidden content.

Set an exact scroll position with scrollTop

For deterministic captures, set the element’s scroll offset in the browser context:

const panel = page.getByTestId('scrolling-container');

await panel.evaluate((element) => {
  element.scrollTop = 500;
});

await panel.screenshot({ path: 'panel-at-500px.png' });

500 is only an example. Select an offset based on the content you need. You can read the dimensions first and clamp the requested position so it cannot exceed the available range:

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
const panel = page.getByTestId('scrolling-container');
const metrics = await panel.evaluate((element) => ({
  scrollTop: element.scrollTop,
  scrollHeight: element.scrollHeight,
  clientHeight: element.clientHeight,
}));

const requestedOffset = 500;
const maxOffset = Math.max(0, metrics.scrollHeight - metrics.clientHeight);
await panel.evaluate((element, offset) => {
  element.scrollTop = offset;
}, Math.min(requestedOffset, maxOffset));

await panel.screenshot({ path: 'panel-positioned.png' });

Setting scrollTop works when the locator resolves to the actual scrolling node. If a wrapper contains the scrollbar, target that wrapper instead.

Scroll like a user with the mouse

When application behavior depends on wheel input, hover the panel and send a wheel event:

Rank #2
Sale
HTML and CSS: Design and Build Websites
  • HTML CSS Design and Build Web Sites
  • Comes with secure packaging
  • It can be a gift option
const panel = page.getByTestId('scrolling-container');
await panel.hover();
await page.mouse.wheel(0, 600);
await page.waitForTimeout(200);
await panel.screenshot({ path: 'panel-after-wheel.png' });

Mouse scrolling is useful for virtualized or infinite lists that load more rows in response to user-like movement. The Playwright input guide covers programmatic and mouse scrolling at playwright.dev/docs/input. Avoid arbitrary sleeps when your app exposes a reliable readiness signal; wait for a row, spinner disappearance, or network state instead.

Capture several positions when the element is taller than its viewport

Because a locator screenshot does not stitch internal scroll positions, capture a sequence of viewports if you need complete coverage:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
import { test } from '@playwright/test';

test('capture every panel segment', async ({ page }) => {
  await page.goto('https://example.com/dashboard');
  const panel = page.getByTestId('scrolling-container');

  const { maxOffset, viewport } = await panel.evaluate((element) => ({
    maxOffset: Math.max(0, element.scrollHeight - element.clientHeight),
    viewport: element.clientHeight,
  }));

  const step = Math.max(1, viewport);
  let index = 0;
  for (let offset = 0; offset <= maxOffset; offset += step) {
    await panel.evaluate((element, value) => {
      element.scrollTop = value;
    }, Math.min(offset, maxOffset));

    // Replace this with a row/asset readiness assertion in your app.
    await panel.screenshot({ path: `panel-${index}.png` });
    index += 1;
  }
});

Adjacent images can overlap or miss content if the scroll step and layout change between captures. For a single composite artifact, record the offsets and compose the images with an image-processing library after capture. The official Locator, screenshots, and input documentation does not specify a built-in locator option that stitches all internal positions.

Wait for lazy, virtualized, and animated content

Lazy-loaded images

Scrolling may be what triggers an image or row to load. After moving the panel, wait for the specific asset or row:

await panel.evaluate((element) => {
  element.scrollTop = element.scrollHeight;
});
await panel.locator('img[data-loaded="true"]').first().waitFor();
await panel.screenshot({ path: 'panel-bottom.png' });

Use an application-specific selector rather than assuming one universal wait condition. For network-driven interfaces, combine a locator assertion with a bounded timeout.

Disable animation for repeatable images

The Locator API supports animations: 'disabled':

await panel.screenshot({
  path: 'panel-stable.png',
  animations: 'disabled',
});

Playwright says this disables CSS animations, CSS transitions, and Web Animations. Finite animations are fast-forwarded to completion; infinite animations are canceled to their initial state during capture.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Element screenshot options worth using

  • path: writes PNG, JPEG, or another format inferred from the filename.
  • animations: 'disabled': removes timing differences from supported animations.
  • mask and maskColor: useful when your test policy allows masking dynamic regions; verify the option against the Playwright version installed in your project.
  • quality: applies to JPEG screenshots when you need smaller files.
  • scale: controls whether output follows device pixels or CSS pixels; choose consistently for visual comparisons.

Consult the versioned Locator API reference for the exact option set supported by your installed Playwright release.

Common failures and precise fixes

The screenshot shows only the top rows

Cause: the panel was never scrolled, or the locator points to a non-scrolling wrapper.

Fix: inspect scrollHeight, clientHeight, and scrollTop; then set scrollTop on the node whose scrollbar moves.

The target is covered by another element

Cause: a sticky header, modal, cookie layer, or other overlay obscures part of the element. The screenshot records what is actually visible.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Fix: close the overlay, hide it in a test-only style, or capture after the UI reaches the intended state. Do not assume Playwright will paint covered pixels.

The locator detaches during capture

Cause: a React/Vue rerender replaced the node after the locator resolved.

Fix: wait for the stable state, use a locator rather than a stale ElementHandle, and retry only around a known transient update. Playwright’s ElementHandle documentation recommends locator-based APIs for this reason; see ElementHandle.

Rank #4
Sale
Web Design with HTML, CSS, JavaScript and jQuery Set
  • Brand: Wiley
  • Set of 2 Volumes
  • A handy two-book set that uniquely combines related technologies Highly visual format and accessible language makes these books highly effective learning tools Perfect for beginning web designers and front-end developers

Scrolling does not load more items

Cause: the list may require pointer focus, a wheel event, an intersection observer, or time for a request to finish.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Fix: hover and use page.mouse.wheel(), wait for a new row or request completion, and verify that the scroll container—not the page—is moving.

Images differ between runs

Cause: animations, fonts, late network responses, device scale, or changing data.

Fix: disable animations, wait for fonts and critical assets, fix viewport and scale, and freeze test data where possible.

Reliability and performance practices

  • Resolve the locator by an accessible name or test ID so layout changes do not silently target the wrong node.
  • Capture only the required panel instead of the entire page to reduce image size and rendering work.
  • For multiple segments, use measured offsets and avoid repeated captures of the same final position.
  • Wait on observable UI conditions rather than long fixed delays; keep a timeout for genuinely slow environments.
  • Record the URL, viewport, device scale, scroll offset, and application revision alongside each artifact so failures are diagnosable.
  • Use a consistent browser, fonts, timezone, and locale for visual regression suites.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Or skip the browser setup: ScreenshotNeo

ScreenshotNeo is a hosted website screenshot API and MCP server. It can capture a URL without you managing Playwright, browsers, or deployment. Its clean-shot pipeline accepts consent banners and removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each step can be turned off. Bot checks, CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and the response reports the page verdict and billing status in X-Page-Verdict and X-Billed headers.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

For a normal page capture, use the API documented at screenshotneo.com/docs/:

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

Python:

import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)

Node.js:

const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);

ScreenshotNeo includes full-page capture with lazy images loaded, CSS-selector element capture, custom JavaScript and CSS, click and wait actions, request blocking, cookies and headers, device presets, retina scale, PDF output, caching with your chosen TTL, bulk capture of up to 100 URLs per call, asynchronous jobs with signed webhooks, signed links, usage reporting, and an MCP server with take_screenshot, get_page_info, and capture_pdf for Claude, Cursor, and other MCP clients.

The Free plan includes 1,000 shots per month without a card. Paid plans start at $5 for 3,000 shots; every feature is included on every plan. Create a free ScreenshotNeo account.

When Playwright is still the better choice

Use Playwright when you need browser-level assertions, authentication flows, application-specific scrolling logic, or a stitched artifact assembled from several internal positions. Use ScreenshotNeo when a URL-to-image request, clean output, failure-aware billing, or an AI-agent workflow is more important than maintaining browser infrastructure.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Frequently Asked Questions

Does fullPage: true capture a scrollable div’s entire contents?

No. It applies to page.screenshot() and captures the full page. A nested scrollable element still requires positioning and separate captures if you need all internal content.

Can Playwright automatically stitch a locator’s hidden scroll range?

The documented locator screenshot API captures the current view; the cited official pages do not document an option that stitches every internal scroll position. Capture segments and compose them when a single image is required.

Should I use an ElementHandle instead of a locator?

Prefer locators. They re-resolve the element and include actionability behavior, while stale handles are more likely to fail after framework rerenders.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Leave a Reply

Your email address will not be published. Required fields are marked *

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

More from the Wire

  1. Shenzhen desk3 min
    HONOR Expands Beyond Smartphones With Humanoid Robot RevealHONOR said it unveiled its first humanoid robot at MWC 2026 and named shopping assistance, workplace inspections, and supportive companionship as intended uses. Later Robotics D1 claims and a reported…
  2. Cupertino desk5 min
    Apple Unveils AirPods Max 2: The Upgrade That Should Have Happened Years AgoAirPods Max 2 adds H2-powered audio features and Apple claims up to 1.5× more effective ANC, but its design, Smart Case, and 20-hour battery rating are unchanged. Wired lossless audio…
  3. Cupertino desk4 min
    Apple’s OLED Touch MacBooks Are Coming—but the Dynamic Island Is the Real GambleApple has not announced an OLED touchscreen MacBook, but reports point to high-end models arriving in late 2026 or early 2027. The reported Mac Dynamic Island could be useful, but…
Recommended PC Tool
Recommended PC Tool
Crashes, No Sound, or Screen Glitches?Free driver scan
PC Slower Than It Used to Be?Free scan - under a minute

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.