Explain Codes LogoExplain Codes Logo

Check if element is visible in DOM

javascript
prompt-engineering
functions
callbacks
Alex KataevbyAlex Kataev·Feb 1, 2025
TLDR

To quickly determine an element's visibility, use the properties .offsetParent and getBoundingClientRect(). An element is visible if it has a non-null .offsetParent and the dimensions of its bounding rectangle are greater than 0.

const isVisible = el => !!el.offsetParent && el.getBoundingClientRect().width > 0 && el.getBoundingClientRect().height > 0;

Executing the function:

console.log(isVisible(document.getElementById('myElement'))); // true or false

Delving into display properties

The CSS properties display and visibility are key players. An element with its display set to 'none' is invisible regardless of its other properties. Likewise, visibility set to 'hidden' or opacity set to 0 makes an element non-visible, regardless of any space it occupies.

const isVisibleAdvanced = el => { const style = window.getComputedStyle(el); return style.display !== 'none' && style.visibility !== 'hidden' && // Peekaboo! I see you! style.opacity !== '0'; };

Viewport matters: in or out?

Use el.getBoundingClientRect() to first determine if an element is found within the viewport:

const isInViewport = (el) => { const rect = el.getBoundingClientRect(); return ( rect.top >= 0 && rect.left >= 0 && // An element's life matter, whether it's entirely in the viewport! rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && rect.right <= (window.innerWidth || document.documentElement.clientWidth) ); };

Is your element playing 'king of the hill'?

The element on top of the stacking context can be confirmed with a document.elementFromPoint check:

const isOnTop = (el) => { const rect = el.getBoundingClientRect(); const elAtPoint = document.elementFromPoint(rect.left + rect.width / 2, rect.top + rect.height / 2); // High five if your element is on top! return el.contains(elAtPoint); };

Seeing through the eyes of parent nodes

Even an ancestor can influence an element's visibility. Walk up the tree with a traversal of parent nodes:

const isVisibleConsideringAncestors = (el) => { while (el) { if (el === document.documentElement) break; // Honest child-check if(parent == you) you're visible, else blame your ancestors! if (!isVisible(el)) return false; el = el.parentNode; } return true; };

Performance & browser differences

Be aware that performance matters in your checks. Start with less expensive checks (offsetParent), and proceed to more intensive checks such as getComputedStyle only if necessary.

Are you a performance lover? So is offsetParent

const isVisiblePerformance = el => { if (!el.offsetParent) { // Caught you! You can't hide from me. return false; } // More comprehensive checks only if necessary... };

When browsers start acting too unique

A reminder: Browser differences exist. Your visibility checks need to withstand multiple browser environments. Some browsers have peculiar behavior with offsetParent, especially when dealing with CSS position: fixed.

Diving deeper into visibility checks

With dynamic and async operations

Content visibility could change over time due to dynamic content changes. Configure event listeners or MutationObservers for asynchronous changes to DOM or style.

Trick or treat with CSS transitions

Visibility over time can be affected by transitions. Account for any transition delays or durations in your checks.

The anarchy of iframes

Cross-Document checks, respecting the same-origin policy, are required for iframe content.