ScreenshotNeo

BlogHow-to

How to Include Hover Menus in Website Screenshots for Product Documentation

Open a hover menu, wait for it to appear, and capture the right area with Playwright or a browser screenshot. Includes reliable code and troubleshooting.

By the ScreenshotNeo team4 October 20268 min read

To include a hover menu in a website screenshot, move the pointer over the menu trigger, wait until the menu is visibly open, then capture the page while the pointer remains over the trigger. With Playwright, use a locator’s hover() method, wait for the menu content to become visible, and take a viewport or element screenshot. Choose a viewport capture when the menu needs page context; choose an element capture when a close-up is clearer.

This works for menus that open on hover. If the site opens its menu on click, reproduce that interaction instead. A screenshot records the page’s current visual state, so capture while the desired menu is open. [Playwright hover API] [Playwright screenshots]

1. Prepare a repeatable capture

  1. Set the browser viewport to the size used in your documentation.
  2. Navigate to the page and identify the menu trigger and the menu content.
  3. Hover the trigger and wait for a meaningful visible condition, such as the menu becoming visible.
  4. Capture the viewport or the menu’s containing element before the pointer leaves the trigger.
  5. Review the saved image at its intended display size. Check that the full menu and enough context are visible, and that the pointer does not cover important text.

Use a condition-based wait for the menu where possible. A fixed delay can help with a known animation, but its correct duration depends on the site and runtime; there is no universal delay that guarantees the menu is ready. Playwright documents hover interactions and screenshot methods, while choosing a suitable readiness condition is specific to the page. [Hover] [Page screenshot API]

2. Capture a hover menu with Playwright

Here is a runnable Node.js example using Playwright’s library. Install it with npm install playwright, then run the script with Node. Replace the URL, trigger locator, and menu locator with ones that match your page.

const { chromium } = require('playwright');

(async () => {
  const browser = await chromium.launch({ headless: true });
  const page = await browser.newPage({
    viewport: { width: 1440, height: 900 },
    deviceScaleFactor: 1,
  });

  try {
    await page.goto('https://example.com', { waitUntil: 'domcontentloaded' });

    const trigger = page.getByRole('link', { name: 'Products' });
    const menu = page.locator('[data-testid="products-menu"]');

    await trigger.hover();
    await menu.waitFor({ state: 'visible' });
    await page.screenshot({ path: 'products-menu.png' });
  } finally {
    await browser.close();
  }
})();

The example uses a role and accessible name for the trigger, and a placeholder test ID for the menu. Use the selectors your page actually exposes. If the menu has no test ID, select it by a stable role, label, or CSS selector. If navigation waits for all network activity and the site keeps connections open, prefer a less restrictive readiness condition such as domcontentloaded and wait explicitly for the menu.

To save only the navigation region, screenshot a container that includes both trigger and dropdown:

await page.locator('header').screenshot({ path: 'navigation-menu.png' });

To capture a specific viewport size, set it when creating the page or context, as in the runnable example. For a long page, a full-page screenshot is available:

await page.screenshot({ path: 'full-page.png', fullPage: true });

Inspect full-page captures carefully: a hover menu is transient, and the output should be checked to make sure the menu remains visible in the image. The screenshot API supports viewport, full-page, and element screenshots; it does not guarantee that every dynamic menu will behave as intended throughout a full-page capture. [Screenshots] [Page screenshot API]

3. Pick the right capture scope

Capture Use it when Check
Viewport The open menu and enough surrounding page context fit on screen. The full dropdown is visible and the trigger’s location is clear.
Element Readers need a close-up of the navigation area. The selected element’s bounds include the entire open menu.
Full page The documentation needs the whole page as well as the menu state. The transient menu appears in the saved output; review the actual image.

For a focused product-documentation image, an element capture can be easier to read, provided its bounds contain the dropdown. For a guide that needs to show where the navigation sits on the page, use a viewport capture. These are editorial choices; match the crop to what the reader needs to understand.

4. Handle different menu behavior

Delayed opening or animation

Wait for the menu itself to become visible rather than guessing how long the animation takes. If the menu becomes visible before its transition finishes, wait for a page-specific end condition or use a short delay based on the known animation. Avoid relying on the same arbitrary sleep across unrelated sites.

Use the site’s actual interaction, such as clicking the trigger, and wait for the menu to become visible. Do not force a hover state when the documented interface is click-driven. Playwright supports interaction methods for reproducing page behavior. [Playwright interaction documentation]

Pointer hides important content

The pointer must remain over the trigger for a hover-open menu to stay open. If it obscures text, check the screenshot at its final display size and choose a crop where the pointer does not cover important information. Do not move it away before capture unless the menu stays open independently of hover.

Responsive or off-screen menu

Confirm the viewport matches the intended documentation target. A narrow viewport may use a different navigation pattern, while a large dropdown can extend beyond the visible area. Adjust the viewport or capture the relevant element, then inspect whether the complete menu is included.

5. Keep screenshots consistent

For visual baselines or repeated documentation captures, keep the browser, operating system, viewport, device scale factor, and capture settings consistent. Rendering can vary with operating system, browser version, settings, hardware, power source, and headless mode, so images captured in different environments may differ even when the page code is unchanged. [Playwright visual comparisons]

Also keep the page state consistent: use the same URL, account or authentication state, and interaction sequence. Wait for the same menu condition each time and use the same screenshot scope. Review changed images before updating documentation or visual baselines; an unexpected difference can be caused by either the page or the capture environment.

6. Troubleshooting

Symptom Likely cause Fix
The menu is missing. The trigger locator did not match, hover did not reach the trigger, or the site uses click to open. Confirm the locator matches the visible control. Reproduce the site’s real interaction and wait for the menu to become visible.
The screenshot shows the trigger but not the dropdown. The capture happened before opening or before the transition finished. Wait for the menu element’s visible state, then capture while the pointer remains over the trigger.
The script times out waiting for the menu. The menu selector is wrong, the menu has not loaded, or the trigger did not open it. Inspect the page’s actual markup and accessible names. Verify the interaction manually, then choose a locator for the menu that exists on that page.
The dropdown is cut off. The viewport is too small or the element screenshot’s target bounds exclude part of the menu. Increase the viewport or select a containing element whose bounds cover the entire dropdown. Inspect the resulting image.
The menu closes during capture. The pointer left the trigger, or capture behavior exposed a site-specific dynamic-state issue. Keep the pointer over the trigger; try a viewport capture and verify the output. If the page requires click, use click instead.
Repeated screenshots differ. Browser or runtime conditions, viewport, device scale, or page state changed. Standardize the environment and interaction sequence, then compare images at the same display size.
Navigation hangs before the hover step. The chosen load condition may wait on resources that remain active. Use a suitable navigation condition and wait for the specific trigger or page content needed before interacting.

7. Performance, reliability, and cost

A local Playwright capture runs a browser and loads the target page, so its time and resource use depend on the page and browser environment. Avoid waiting for more page activity than the task needs: navigate to an appropriate readiness point, then wait for the trigger and menu conditions. For reliable documentation, prefer visible-state checks and inspect the saved result rather than treating a completed script as proof that the menu rendered correctly.

Playwright is an open-source browser automation framework; the cited procedural material does not specify a per-screenshot service price. Your operational cost depends on where and how you run the browser. For repeatable visual comparisons, browser and runtime consistency matters as much as the capture code. [Visual comparisons]

Or skip the browser setup

ScreenshotNeo is a website screenshot API and MCP server from Yorker Media. A single GET request captures a URL as PNG, JPEG, WebP, or PDF. It provides controls for viewport, device presets, full-page capture, selectors, custom CSS and JavaScript, waits, and more. See the ScreenshotNeo API documentation for parameters and configuration.

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
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)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
const fs = await import('node:fs/promises');
await fs.writeFile('shot.webp', Buffer.from(await res.arrayBuffer()));

For a hover-open menu, a browser automation workflow can perform the hover before asking ScreenshotNeo to capture the page; the one-call screenshot request itself does not perform the pointer interaction. Cookie banners, popups, and chat widgets are removed before the shot. Bot checks, blank pages, and failed loads are never billed. Its MCP server lets AI agents take screenshots. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000. Create a free ScreenshotNeo account.

FAQ

Can Playwright screenshot a hovered element?

Yes. Hover the locator, wait for the desired state, then screenshot the page or a containing element. Ensure the selected element includes the menu.

Should I move the pointer away before capturing?

No, if the menu stays open only while its trigger is hovered. Keep the pointer on the trigger until capture. Move it away only when you want to remove hover styling and the menu does not depend on hover.

Is a full-page screenshot always best for product documentation?

No. Use it when the full page is needed, but check that the transient hover state appears in the output. A viewport or navigation element capture may make the menu easier to understand.

Why does the same screenshot look different on another machine?

Rendering can vary with the browser, operating system, settings, hardware, and headless mode. Keep the capture environment consistent for visual comparisons.