How to Take a Screenshot of a Specific HTML Element

By Jeffrey Needles

September 02, 2026
Tutorial
Screenshot

How to Take a Screenshot of a Specific HTML Element

Most screenshot examples capture the browser viewport or the entire page. That is useful for a landing page, but it is too much when you only need one chart, receipt, product card or section of a report.

Puppeteer and Playwright can take a screenshot of an element directly. You give them a selector, they find the element and crop the image to its bounds. The basic capture only takes a few lines. Most problems come from the selector or the element's bounds.

Here is the page used in the examples. We only want the revenue chart marked Screenshot target.

A dashboard with a revenue chart marked as the element to capture

Note

The examples use Chromium with Puppeteer, PuppeteerSharp and Playwright. HTML/CSS to Image uses Chromium too, so the same selector and layout issues apply there.

Step 1: Give the Element a Stable Selector

If you control the HTML, add an attribute specifically for screenshots:

<section
  class="report-card"
  data-screenshot-target="revenue-chart"
>
  <!-- Chart, labels and legend -->
</section>

The class may change when the design changes. A selector such as .dashboard > main > section:nth-child(3) is even easier to break. A data attribute makes the intent clear and gives the screenshot code a stable target:

[data-screenshot-target="revenue-chart"]

Try to make the selector match exactly one element. Playwright throws a strict-mode error when an action such as screenshot() matches more than one element. Puppeteer returns the first match from waitForSelector(), which can silently capture the wrong card if the page changes.

When you do not control the page, use the shortest selector that uniquely identifies the content. An element ID or a meaningful data attribute is usually a better choice than a long chain of classes and nth-child() selectors.

Step 2: Take the Element Screenshot

Assume the page is already open and its dynamic content has finished rendering. Each example finds the same chart and saves it as a PNG.

const selector = '[data-screenshot-target="revenue-chart"]';
const target = await page.waitForSelector(selector, {
  visible: true,
  timeout: 30_000,
});

await target.screenshot({
  path: "revenue-chart.png",
});

Puppeteer's ElementHandle.screenshot() and Playwright's locator.screenshot() scroll the target into view before capturing it. PuppeteerSharp's IElementHandle.ScreenshotAsync() does the same.

This is the resulting element screenshot:

The revenue chart cropped exactly to the bounds of its HTML element

Notice that the shadow is gone and the green badge at the top is clipped. The screenshot uses the element's box. A shadow does not make that box larger, and the badge is positioned partly outside it.

The box in this context is the element's border box. It includes the content, padding and border. CSS margins and box shadows sit outside it, so they do not make an element screenshot larger:

Diagram showing that an element screenshot includes the content, padding and border, but not margin or box shadow

Step 3: Add Space Around the Crop

If you own the HTML, the easiest way to add padding is to put a wrapper around the target and screenshot the wrapper:

<div class="screenshot-frame">
  <section class="report-card">
    <!-- Chart, labels and legend -->
  </section>
</div>
.screenshot-frame {
  padding: 30px;
  background: #f1f4f8;
}

This also gives you control over the color behind the element. It is usually simpler than calculating a larger crop in code.

For a page you cannot change, get the element's bounding box and add padding to the clip rectangle:

const padding = 30;

await target.scrollIntoView();
const box = await target.boundingBox();

if (!box) {
  throw new Error("Screenshot target is not visible");
}

const x = Math.max(0, box.x - padding);
const y = Math.max(0, box.y - padding);

await page.screenshot({
  path: "revenue-chart-padded.png",
  captureBeyondViewport: true,
  clip: {
    x,
    y,
    width: box.x + box.width + padding - x,
    height: box.y + box.height + padding - y,
  },
});

The padded version includes the badge, the shadow and some of the surrounding page color:

The same revenue chart captured with 30 pixels of padding around it

The Math.max() and Math.Max() calls keep the crop from starting at a negative coordinate when the element is close to the top or left edge of the page.

Hidden, Covered and Scrollable Elements

An element has to produce a visible box before it can be captured. display: none, visibility: hidden and a zero-sized container do not give the browser anything useful to screenshot. Open the accordion, modal or menu first, then wait for the target to become visible.

An element can also be visible but covered. A sticky header, cookie banner or modal backdrop may sit over it after the browser scrolls it into view. Element screenshots capture the pixels that are actually on the page, including anything layered above the target. Dismiss the overlay or hide it with screenshot-specific CSS.

Scrollable containers are another special case. If the selected element has overflow: auto, its screenshot only includes the part currently visible inside that element. To capture all of its contents, temporarily remove the scrolling limit:

.screenshot-mode .scrollable-report {
  max-height: none !important;
  overflow: visible !important;
}

Apply the class before measuring or capturing the element. Changing overflow can change the element's size, so an old bounding box is no longer valid.

Transparent Element Screenshots

PNG and WebP can keep transparent pixels. JPEG cannot. In Puppeteer, set omitBackground: true in the element screenshot options. Playwright uses the same option, and PuppeteerSharp and Playwright .NET expose it as OmitBackground.

await target.screenshot({
  path: "revenue-chart.png",
  omitBackground: true,
});

This removes the browser's default page background. It does not remove a background declared on the element itself. If .report-card has background: white, the card will still be white.

For a padded transparent crop, make the wrapper background transparent and capture it as PNG or WebP. Check the result in an editor with a transparency grid. A transparent PNG displayed on a white webpage can look exactly like an image with a white background.

Take an Element Screenshot with HTML/CSS to Image

HTML/CSS to Image accepts a CSS selector parameter for both HTML and URL screenshots. It crops the result to the matching element:

{
  "url": "https://example.com/dashboard",
  "selector": "[data-screenshot-target='revenue-chart']"
}

The same parameter works when you send HTML directly:

{
  "html": "<section class='report-card'>...</section>",
  "selector": ".report-card"
}

For a URL screenshot, the css request parameter can add padding just for the render. You do not have to change the source page. If the target already has a suitable parent, select that parent and add the padding there:

{
  "url": "https://example.com/dashboard",
  "selector": ".revenue-chart-frame",
  "css": ".revenue-chart-frame { padding: 30px !important; box-sizing: content-box !important; }"
}

The parent becomes the crop boundary, and its padding creates the extra space around the chart. box-sizing: content-box adds that padding outside the parent's existing content area. The padded area uses the parent's background, which you can also set in the injected CSS.

You can also add a margin to the child and select its parent, but that depends on the parent's layout. Vertical margins can collapse in normal block layout, and fixed-size or clipped parents may still cut them off. Padding on the selected parent is more predictable.

This works well when you only need a little breathing room. It will not include the full extent of a box shadow that falls outside the selected parent's bounds. Use a larger wrapper or a custom clip for that. Set transparent_background: true if the page around the selected element should be transparent.

The selector decides where to crop. It does not decide when the content is ready. If the element contains API data, images or charts, use a readiness signal before capturing it. How to Wait for a Page to Finish Rendering Before Taking a Screenshot covers that part.

Common Problems

The Selector Matches More Than One Element

Use a unique ID or data attribute. If multiple matches are intentional, choose one explicitly with Playwright's .first(), .last() or .nth(). With Puppeteer, use page.$$(selector) and pick the expected handle rather than relying on the first match.

The Element Screenshot Is Blank

Check whether the element has a nonzero width and height. A container can exist in the DOM before its content is rendered. Also check for display: none, visibility: hidden and a parent that hides the element.

The Shadow or Tooltip Is Cut Off

Shadows, tooltips and absolutely positioned children can extend outside the element's bounding box. Screenshot a padded wrapper or use a larger clip rectangle.

The Crop Changes Between Runs

Set a consistent viewport before loading the page. Responsive layouts can move the target or change its dimensions. Wait for fonts, images and dynamic content, and disable animations when the library supports it.

Frequently Asked Questions

Does an Element Screenshot Include CSS Margins and Box Shadows?

Usually not. The crop follows the element's bounding box. Margins and box shadows are outside that box, so add a wrapper or a padded clip if they should appear in the image.

Can I Screenshot an Element That Is Outside the Viewport?

Yes. Puppeteer and Playwright scroll the element into view before taking an element screenshot. The element still has to be visible and have a nonzero size.

Can I Capture All the Content Inside a Scrollable Element?

Not with a normal element screenshot. It captures the visible portion of the scroll container. Remove its fixed height and overflow rules before capturing if you need all of the content.

Can I Return the Screenshot Without Saving a File?

Yes. Puppeteer and Playwright return the image bytes when no path is supplied. PuppeteerSharp provides ScreenshotDataAsync(), and Playwright .NET's ScreenshotAsync() returns a byte array.

Element Screenshot or Custom Clip?

Use the built-in element screenshot method when the element's border box is the crop you want. Add a wrapper when you control the HTML and need padding. Use a bounding box and custom clip when you do not control the page or need exact coordinates.

With HTML/CSS to Image, pass the same CSS selector in the selector parameter. The API handles the browser and returns the cropped image without requiring a Puppeteer or Playwright worker.

Loading newsletter signup…

Please wait a moment.

Have a question?

We'd love to hear about what you're building.

Contact us

Get Started

You'll be up and running in 5 minutes.

Grab an API Key

Keep reading

More posts

View all posts
Get Started Now

NO CREDIT CARD NEEDED. 50 FREE IMAGES EVERY MONTH.