How can I check that an element is visible with Puppeteer and pure JavaScript?

I wish to check that a DOM element is visible with Puppeteer and pure JavaScript (not jQuery), how can I do this? By visible I mean that the element is displayed through CSS, and not hidden (f.ex. by display: none).

For example, I can determine whether my element #menu is not hidden via CSS rule display: none, in the following way:

const isNotHidden = await page.$eval('#menu', (elem) => {
  return !== 'none'

How can I determine in general though if the element is hidden or not, and not just through display: none?

I found that Puppeteer has an API method for this purpose: Page.waitForSelector, via its visible option. I wasn’t aware of the latter option, but it lets you wait until an element is visible.

await page.waitForSelector('#element', {
  visible: true,

Conversely you can wait for an element to be hidden, via the hidden option.

I think this is the idiomatic answer, with regards to the Puppeteer API. Thanks to Colin Cline though as I think his answer is probably useful as a general JavaScript solution.

One is by checking its display style value.
Second is by checking its height, for exp if the element is a child of an element which is display: none, the offsetHeight will be and thus you know the element is not visible despite its display value. opacity: 0 is not considered as hidden element so we will not checking it.

const isNotHidden = await page.$eval('#menu', (elem) => {
    return window.getComputedStyle(elem).getPropertyValue('display') !== 'none' && elem.offsetHeight

You can check elem.offsetWidth as well and is not bad before any calculation, check if element exist or not.

Read More:   What the difference between window.setTimeout() and setTimeout()?

Use boundingBox()

This method returns the bounding box of the element (relative to the main frame), or null if the element is not visible.


The current accepted answer involves waiting for an element to appear and become visible.

If we are not interested in waiting on the element, and we would simply like to test the visibility of the element, we can use a combination of getComputedStyle() and getBoundingClientRect() to test whether or not the element is visible.

We can first check that the visibility is not set to hidden.

Then we can validate that the bounding box is visible by checking that the bottom, top, height, and width attributes are not set to (this will filter out elements that have display set to none as well).

const element_is_visible = await page.evaluate(() => {
  const element = document.querySelector('#example');
  const style = getComputedStyle(element);
  const rect = element.getBoundingClientRect();

  return style.visibility !== 'hidden' && !!(rect.bottom || || rect.height || rect.width);

Maybe you can using elementHandle.boundingBox() (thank to @huypham idea)

It will return a Promise that show a bounding box of the element (relative to the main frame), or null if the element is not visible.

The snippet example:

      const loadMoreButton = await getDataPage.$(

      const buttonVisible = await loadMoreButton.boundingBox();

      if (buttonVisible) {
        await => {
          console.log('💥💥💥: ' + e)

based on playwright’s logic for checking if the element is visible –

function isVisible(element: Element): boolean {
    // Note: this logic should be similar to waitForDisplayedAtStablePosition() to avoid surprises.
    if (!element.ownerDocument || !element.ownerDocument.defaultView)
      return true;
    const style = element.ownerDocument.defaultView.getComputedStyle(element);
    if (!style || style.visibility === 'hidden')
      return false;
    const rect = element.getBoundingClientRect();
    return rect.width > 0 && rect.height > 0;

Apparently here’s how jQuery does it:

visible = await page.evaluate((e) => e.offsetWidth > 0 && e.offsetHeight > 0, element)

If you just want to know if an element is visible or not then you can use this function. You should make sure that the page is ready before calling this function. You can do that by using waitForSelector on other elements you expect to be visible.

async function isVisible(page, selector) {
  return await page.evaluate((selector) => {
    var e = document.querySelector(selector);
    if (e) {
      var style = window.getComputedStyle(e);

      return style && style.display !== 'none' && style.visibility !== 'hidden' && style.opacity !== '0';
    else {
      return false;
  }, selector);

// Example usage:
var myElementIsVisible = await isVisible(page, '#visibleOrNot');

if (myElementIsVisible) {
// Interact with #visibleOrNot

this code definitely help you.
It basically means the element is already available on the page but is not visible yet or in CSS, the display property is set as none or visibility is hidden. Now, while writing our tests, we assume that as soon as the element is available, do an action on it like clicking or typing. But as this element is not yet visible, Puppeteer fails to perform that action.

async function isLocatorReady(element, page) {
  const isVisibleHandle = await page.evaluateHandle((e) => 
    const style = window.getComputedStyle(e);
    return (style && style.display !== 'none' && 
    style.visibility !== 'hidden' && style.opacity !== '0');
 }, element);
  var visible = await isVisibleHandle.jsonValue();
  const box = await element.boxModel();
  if (visible && box) {
    return true;
  return false;

The answer @aknuds1 gave is perfect but you may make it even more convenient for yourself by creating a helper such as this one. This resolves to true if the element is visible and to false otherwise.

function isElementVisible(page, selector, timeout = 150) {
    return new Promise((resolve) => {
        page.waitForSelector(selector, {visible: true, timeout}).then(() => {
        }).catch(() => {


in pure JS with Puppeteer

let isVisible = await isElementVisible(page, selector)
isVisible = await isElementVisible(page, selector, 300)

and if you happen to use Jest or another framework

expect(await isElementVisible(page, selector)).toBeTrue();

in the case of Jest (and most other frameworks), you can go even further and create a custom matcher to extend the existing ones. (

    async toHaveVisible(page, selector, timeout = 150) {
        let isVisible = await isElementVisible(page, selector, timeout);

        if (isVisible) {
            return {
                message: () => `expected ${selector} not to be visible`,
                pass: true
        } else {
            return {
                message: () => `expected ${selector} to be visible`,
                pass: false
await expect(page).toHaveVisible(selector);
await expect(page).not.toHaveVisible(anotherSelector);
await expect(page).not.toHaveVisible(yetAnotherSelector, 300);

const firstName= await page.$('[name=firstName]')

I would use @aknuds1 ‘s approach, but you can also do the following.

expect((await page.$('#element')) !== null).toEqual(true)

If you are fetching a resource asynchronously, be aware that the above expectation may not pass, since it won’t wait for the changes to reflect on the UI. That’s why this approach may not be preferred in this scenario.

Read More:   Google Maps: Auto close open InfoWindows?

The answers/resolutions are collected from stackoverflow, are licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0 .

Similar Posts