page.screenshot({ fullPage: true }) captures the full scrollable page, but it does not make a virtualized table render rows that are absent from the DOM. To capture every row, either use an application-supported test mode that renders all rows or scroll the table through its logical row range and capture overlapping viewport segments. In both cases, verify row-index coverage; a successful screenshot call alone does not prove that every row was loaded.
Why fullPage does not capture every virtualized row
Playwright describes a full-page screenshot as a capture of the full scrollable page, “as if you had a very tall screen and the page could fit it entirely.” That changes the screenshot extent; it does not tell the table application to create rows it has virtualized out of the DOM. Playwright screenshot documentation documents page.screenshot({ fullPage: true }), not a universal virtualization override.
As an Amazon Associate I earn from qualifying purchases.
There is a related limitation for element captures: Playwright’s Locator API says a screenshot of a scrollable element contains only the content currently scrolled into view. Taking a screenshot of the table locator does not automatically expand its internal scroll positions into one tall image. See the Locator screenshot API.
The key distinction is between the page’s scrollable height and the table’s logical data. A virtualized grid may reuse a small set of DOM elements as you scroll. The screenshot can faithfully capture what is rendered while still omitting rows that have not been brought into view.
#1 Best Overall
- CRISP CLARITY: This 23.8″ Philips V line monitor delivers crisp Full HD 1920x1080 visuals. Enjoy movies, shows and videos with remarkable detail
- INCREDIBLE CONTRAST: The VA panel produces brighter whites and deeper blacks. You get true-to-life images and more gradients with 16.7 million colors
- THE PERFECT VIEW: The 178/178 degree extra wide viewing angle prevents the shifting of colors when viewed from an offset angle, so you always get consistent colors
- WORK SEAMLESSLY: This sleek monitor is virtually bezel-free on three sides, so the screen looks even bigger for the viewer. This minimalistic design also allows for seamless multi-monitor setups that enhance your workflow and boost productivity
- A BETTER READING EXPERIENCE: For busy office workers, EasyRead mode provides a more paper-like experience for when viewing lengthy documents
Choose a capture strategy
| Approach | Logical coverage | Image and readability | UI fidelity | Operational trade-offs |
|---|---|---|---|---|
| Render all rows in an app-supported test mode | Can include the full dataset in one capture; verify the first and last logical row and expected count. | May create an extremely tall image that is difficult to inspect or share. | Depends on whether the test mode preserves the styles and layout you need to validate. | Can be simpler than scrolling, but large DOMs can affect performance and memory. |
| Scroll and capture viewport segments | Can cover the logical range when each segment’s row indices are recorded and checked for gaps. | Produces manageable pieces; overlap helps with stitching, but sticky headers may repeat. | Shows the table in its normal virtualized state as it scrolls. | Requires a reliable render/readiness signal, more capture time, and careful stitching if one image is required. |
These are practical trade-offs, not published Playwright benchmarks. For a single image where the test environment can safely render all data, start with the application’s supported full-render mode. For fidelity to the normal virtualized interface or very large tables, capture segments and verify their logical coverage.
Before writing the capture loop
Find the real scroll container
Inspect the page and identify the element whose scrollTop changes when you scroll the table. It may be a nested grid viewport rather than the page or the outer table wrapper. A page-level full-page screenshot and a screenshot of a table locator are different targets; neither automatically traverses every internal table scroll position.
Find stable logical row identifiers
Use application-provided row indices, such as meaningful aria-rowindex values or data attributes, to record which logical rows are visible in each capture. Validate that an attribute represents the row’s true dataset position, not merely a recycled DOM slot. Also establish the expected first row, final row, and total range from the application or test fixture.
Recommended Free Tools
Rank #2
- CRISP CLARITY: This 22 inch class (21.5″ viewable) Philips V line monitor delivers crisp Full HD 1920x1080 visuals. Enjoy movies, shows and videos with remarkable detail
- 100HZ FAST REFRESH RATE: 100Hz brings your favorite movies and video games to life. Stream, binge, and play effortlessly
- SMOOTH ACTION WITH ADAPTIVE-SYNC: Adaptive-Sync technology ensures fluid action sequences and rapid response time. Every frame will be rendered smoothly with crystal clarity and without stutter
- INCREDIBLE CONTRAST: The VA panel produces brighter whites and deeper blacks. You get true-to-life images and more gradients with 16.7 million colors
- THE PERFECT VIEW: The 178/178 degree extra wide viewing angle prevents the shifting of colors when viewed from an offset angle, so you always get consistent colors
Use the table’s readiness signal
After scrolling, wait for the component’s own signal that the new range has rendered and settled. This might be a test hook, a known row index appearing, or an application state exposed to the test. A fixed delay is not a universal readiness guarantee: data fetching, rendering, and animation timing depend on the application.
Method 1: render all rows through an application-supported test mode
If the table component or application offers a supported test configuration that disables virtualization or renders the full dataset, use that rather than trying to manipulate undocumented internals. The exact flag, selector, or component hook is application-specific; Playwright does not define one generic option.
- Enable the supported test configuration. Set it through the app’s test setup or component configuration, not by guessing at a library-specific property.
- Wait for the complete dataset. Use the application’s data-ready signal and verify that the expected first and final logical rows are present.
- Capture the page or table. Use
page.screenshot({ fullPage: true })for the full scrollable page, or a locator screenshot when the desired target is the table element. The element capture still reflects the element’s rendered dimensions and behavior. - Review dimensions and fidelity. Check the resulting image’s height, legibility at the size it will be viewed, styles, sticky elements, and whether test mode changes the production layout in ways that matter to the screenshot.
import { test, expect } from '@playwright/test';
test('capture the fully rendered table', async ({ page }) => {
// The application must provide this test mode and readiness signal.
await page.goto('https://example.com/table?testMode=allRows');
await page.getByTestId('table-ready').waitFor();
const rows = page.locator('[data-logical-row-index]');
await expect(rows.first()).toHaveAttribute('data-logical-row-index', '0');
await expect(rows.last()).toHaveAttribute('data-logical-row-index', '999');
await page.screenshot({ path: 'table.png', fullPage: true });
});
The URL, readiness marker, row selector, and index range above are examples, not Playwright conventions. Replace them with the application’s actual test mode and logical row identifiers. If the full-render mode causes an impractically large DOM or image, use segmented capture instead.
Rank #3
- Clear visuals. Fluid motion: A 144Hz refresh rate and 1ms MPRT deliver smooth, tear‑free motion across work, gaming, and streaming for clearer, more fluid viewing.
- Eye comfort: TÜV Rheinland 3‑star* certification reduces harmful blue light while preserving stunning color quality without compromise. *TÜV Rheinland 3-star eye comfort certification.
- Wide viewing angle: Get consistent views across a wide 178° /178° viewing angle.
- In-Plane Switching (IPS): See excellent color accuracy and consistency across wide viewing angles with In-plane Switching (IPS) technology.
- Ultra-thin bezels: Maximize your viewing experience with thin bezels.
Method 2: scroll the virtualized table and capture segments
When rendering all rows is unavailable or undesirable, scroll the actual table container in increments, wait for the next logical range to settle, and capture its viewport. The loop below deliberately uses application-specific selectors and a readiness function: there is no universal selector or event for virtualized tables.
Free tools Windows power users keep installed
One-click scans. No signup required.
import { test, expect } from '@playwright/test';
test('capture every logical table row in segments', async ({ page }) => {
await page.goto('https://example.com/table');
const scroller = page.locator('[data-testid="table-scroll-container"]');
await expect(scroller).toBeVisible();
await page.getByTestId('table-ready').waitFor();
const totalRows = 1000; // Obtain this from the fixture or application.
const step = 400; // Choose based on viewport size and desired overlap.
const captures = [];
for (let top = 0; top < totalRows; top += step) {
await scroller.evaluate((element, scrollTop) => {
element.scrollTop = scrollTop;
}, top);
// Replace with a signal that confirms this range has rendered and settled.
await page.getByTestId('visible-range-ready').waitFor();
const visibleIndices = await scroller
.locator('[data-logical-row-index]')
.evaluateAll(elements => elements.map(element =>
Number(element.getAttribute('data-logical-row-index'))
));
if (!visibleIndices.length || visibleIndices.some(Number.isNaN)) {
throw new Error(`No usable logical row indices at scrollTop ${top}`);
}
const first = Math.min(...visibleIndices);
const last = Math.max(...visibleIndices);
const path = `table-${String(captures.length).padStart(3, '0')}-${first}-${last}.png`;
await scroller.screenshot({ path });
captures.push({ path, first, last, indices: visibleIndices });
}
const covered = new Set(captures.flatMap(capture => capture.indices));
const missing = Array.from({ length: totalRows }, (_, index) => index)
.filter(index => !covered.has(index));
if (missing.length) {
throw new Error(`Missing logical rows: ${missing.slice(0, 20).join(', ')}`);
}
});
This is a pattern to adapt, not drop-in code for an unknown grid. Some tables scroll in pixels while row indices are data positions; others load data asynchronously, use non-contiguous indices, or expose total count through separate state. Choose the scroll step using the actual container and row behavior, and ensure adjacent captures overlap enough to detect gaps and support stitching. The sample checks coverage only if the attributes identify stable logical rows and the expected index range is correct.
Capture only after the range changes
A readiness marker should confirm the intended range, not merely that the table was ready initially. For example, expose a test attribute for the first and last rendered logical index and wait until it reflects the target range after scrolling. If rows can be recycled, wait for their logical indices to update before capturing.
Rank #4
- CURVED FOR ENHANCED ENGAGEMENT: An immersive viewing experience with a curved monitor that wraps more closely around your field of vision; It creates a wider view, enhancing depth perception and minimizing peripheral distraction
- SMOOTH PERFORMANCE FOR SEAMLESS CONTENT: Stay in the action when playing games, watching videos, or working on creative projects; The 100Hz refresh rate reduces lag and motion blur so you don't miss a thing in fast-paced moments¹
- MORE GAMING POWER: Gain the edge with optimizable game settings; Color and image contrast can be adjusted to see scenes more vividly and spot enemies hiding in the dark; Game Mode adjusts any game to fill the screen so you can view every detail²
- KEEP IT EASY ON THE EYES: Care for your eyes and stay comfortable, even during long sessions; Advanced eye comfort technology certified by TÜV reduces eye strain by minimizing blue light and reducing irritating screen flicker²
- INCREASED VERSATILITY: Connect to more; Plug devices straight into your monitor for increased flexibility, making your computing environment even more convenient
Handle the bottom boundary
Scrolling by a fixed step may not land exactly at the final position because the scroll height and viewport height differ. After the loop, explicitly scroll to the container’s maximum scrollTop, wait for the final range, capture it, and verify that it includes the expected last row. The sample’s row-index coverage check will expose missing rows if the indices and total are valid.
Stitch only when one image is necessary
Keep the individual viewport screenshots as the source of truth. If a single composite is needed, stitch them with enough overlap to align row boundaries. Decide whether to crop repeated sticky headers, and check for discontinuities caused by changing column widths, fonts, scrollbars, or browser rendering. Playwright does not provide a universal virtual-table stitching API.
What to verify before calling the screenshot complete
- Expected range: Confirm the first and final logical rows and the expected dataset count.
- No gaps: Check the union of row indices across segments; a successful screenshot call is not a coverage check.
- Loaded data: Confirm asynchronous data and any row-level content have finished loading before capture.
- Correct target: Ensure you scrolled the table’s actual container, not the page or an outer wrapper.
- Visual integrity: Inspect overlap, sticky headers, clipped columns, and readability at the intended viewing size.
- Browser scope: If screenshots must match across supported browsers, run the check in those browsers; layout and rendering differences can affect segment alignment.
Troubleshooting missing or incomplete rows
| Symptom | Likely cause | Fix |
|---|---|---|
| The screenshot contains only the first visible rows. | fullPage enlarged the page capture, but the table virtualized rows outside its current range. |
Use an app-supported all-rows test mode or scroll the table container and capture each settled range. |
| Every segment looks the same. | The script may be scrolling the wrong element, or the table has not updated before capture. | Confirm the actual container’s scrollTop changes; wait for an app-specific visible-range signal. |
| Some rows are missing between screenshots. | The scroll step may exceed the rendered range, or the readiness signal may fire too early. | Increase overlap, record logical indices for each segment, and wait until the intended range is rendered before saving. |
| The final rows are absent. | The last scroll position may not reach the container’s maximum, or the bottom data is still loading. | Scroll explicitly to maximum scrollTop, wait for the final data/render signal, and confirm the expected last logical index. |
| The image is enormous or difficult to read. | Rendering all rows creates a very tall screenshot, or it is being viewed scaled down. | Prefer segmented captures for review, or render all rows only where a single image is required and remains legible. |
| Stitched output repeats or cuts off a header. | Sticky headers appear in each viewport or the overlap/crop does not align. | Choose a consistent header treatment and adjust overlap and crop after inspecting adjacent segments. |
Performance, reliability, and cost considerations
There is no universal row count, capture time, or reliability figure for this workflow: the result depends on the table implementation, data loading, test environment, browser, and image size. Full rendering trades extra DOM and potentially large image dimensions for fewer capture steps. Segmented capture controls image size but adds scrolling, waits, screenshots, and coverage validation. Avoid treating an arbitrary pause or a successful API call as evidence that all data is present.
For repeatable visual evidence, make the data deterministic where possible, keep the expected logical range explicit, and preserve the row-index coverage check alongside the screenshot artifacts. If the test needs a single image, decide whether the application’s all-rows mode retains the UI appearance being tested; if it does not, segmented images may be more faithful.
Best Value
- 【INTEGRATED SPEAKERS】Whether you're at work or in the midst of an intense gaming session, our built-in speakers provide rich and seamless audio, all while keeping your desk clutter-free.
- 【EASY ON THE EYES】 Protect your eyes and enhance your comfort with Blue-Light Shift technology. This feature reduces harmful blue light emissions from your screen, helping to alleviate eye strain during long hours of use and promoting healthier viewing habits.
- 【WIDEN YOUR PERSPECTIVE】Our sleek minimal bezel design ensures undivided attention. The nearly bezel-free display seamlessly connects in a dual monitor arrangement, delivering an unobstructed view that lets you focus on more at once, completely distraction-free.
Or skip the browser setup
If your goal is to capture a page rather than validate a virtualized grid’s logical row coverage, ScreenshotNeo offers a one-request screenshot API. A screenshot service captures the page it receives; it does not establish that a virtualized table rendered every logical row, so use the Playwright verification workflow above when completeness is the requirement.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://example.com/table -o shot.webp
See the ScreenshotNeo API documentation for request options. ScreenshotNeo removes cookie banners, newsletter popups, and chat widgets before capture; bot checks, blank pages, and failed loads are never billed. Its MCP server provides screenshot tools for AI agents, and the Free plan includes 1,000 shots per month with no card required; paid plans start at $5 for 3,000 shots. Sign up for 1,000 free screenshots a month, with no card.
Quick wins for a faster PC:
Clear out junk files and repair common Windows errorsFree Scan →Scan for outdated or missing drivers - takes under a minuteDriver Scan →Frequently Asked Questions
Does Playwright have a universal option to disable table virtualization?
No. Playwright documents screenshot behavior, not a generic virtualization-control setting. Use a test mode provided by the application or component, or capture while scrolling.
Can I use page.screenshot({ fullPage: true }) for a normal, non-virtualized table?
Yes, it captures the full scrollable page. For a virtualized table, however, it does not itself cause offscreen logical rows to be rendered.
Quick Recap
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.




