Skip to main content

How to Find the Highest z-index on a Page in JavaScript

When you are dynamically creating UI elements like modals, pop-ups, or toasts, you often need to ensure they appear on top of all other content. To do this reliably, you must find the current highest z-index value on the page and set your new element's z-index to a value greater than that.

This guide will teach you a robust, modern method for scanning the DOM to find the maximum z-index. You will learn why this task is more complex than it seems and the critical performance considerations to keep in mind.

The Core Challenges

Finding the highest z-index is not as simple as reading a single property. There are two main challenges:

  1. Styles Can Come from Anywhere: A z-index can be set in an inline style attribute, an internal <style> block, or an external CSS file. You cannot simply use element.style.zIndex, as this only reads inline styles. You must use window.getComputedStyle() to get the final, rendered style.
  2. z-index Defaults to auto: For most elements, getComputedStyle(element).zIndex will return the string "auto", not a number. When you try to parse this (parseInt('auto')), you get NaN (Not-a-Number), which you must handle correctly.

The most reliable solution is to iterate through all elements on the page, get their computed z-index, and keep track of the highest numeric value you find. This function is a clear and readable implementation of that logic.

Example of reausable function:

/**
* Finds the highest z-index value currently on the page.
* @returns {number} The maximum z-index found.
*/
function findMaxZIndex() {
// 1. Get all elements on the page
const allElements = document.querySelectorAll('body *');
let maxZ = 0;

// 2. Loop through them
for (const element of allElements) {
// 3. Get the computed z-index
const zIndex = window.getComputedStyle(element).zIndex;

// 4. Parse it as a number, ignoring 'auto' (which becomes NaN)
const zIndexNum = parseInt(zIndex, 10);

// 5. Keep track of the highest valid number
if (!isNaN(zIndexNum) && zIndexNum > maxZ) {
maxZ = zIndexNum;
}
}

return maxZ;
}

Solution:

// Example Usage:
const highestZIndex = findMaxZIndex();

console.log(`The highest z-index on the page is: ${highestZIndex}`);

// To place a new element on top of everything:
const myModal = document.getElementById('my-modal');
myModal.style.zIndex = highestZIndex + 1;

How the Solution Works

  1. document.querySelectorAll('body *'): This selects every single element that is a descendant of the <body>.
  2. for (const element of allElements): We loop through this collection of elements.
  3. window.getComputedStyle(element).zIndex: For each element, we get its final, rendered z-index value as a string.
  4. parseInt(zIndex, 10): We attempt to convert this string to a base-10 integer. If zIndex was "auto", this results in NaN.
  5. !isNaN(zIndexNum) && zIndexNum > maxZ: This is the core logic. We first check if the result is a valid number (not NaN). If it is, we then check if it's greater than the highest value we've seen so far. If both are true, we update our maxZ.
  6. return maxZ: After checking all elements, maxZ will hold the highest numeric z-index found. We initialize it to 0 to handle cases where no elements have a z-index.

A Note on the "One-Liner" Approach

You may see this logic written as a dense, functional one-liner. While concise, it is often harder to read and debug.

function getMaxZIndexOneLiner() {
return Math.max(
...Array.from(document.querySelectorAll('body *'), el =>
parseInt(window.getComputedStyle(el).zIndex)
).filter(zIndex => !isNaN(zIndex)),
0
);
}

This code performs the exact same steps as our more readable function but uses Array.from with a mapping function, filter, and the spread (...) operator. For maintainability, the step-by-step for...of loop is often preferred.

Performance Considerations

The biggest drawback of this method is performance. The document.querySelectorAll('body *') command can be very slow on large, complex web pages with thousands of elements, as the script must iterate over every single one.

  • For most websites and applications, this is perfectly fine. The operation is fast enough that it won't be noticeable.
  • For complex Single-Page Applications (SPAs) or pages with infinite scrolling, running this function frequently could become a bottleneck.

In such high-performance scenarios, a more advanced strategy might be needed, such as only querying elements that are likely to have a z-index (e.g., those with position: absolute or fixed), or maintaining the max z-index in a global state manager.

Conclusion

Finding the highest z-index requires a full DOM scan that correctly handles computed styles and non-numeric values.

  • The most reliable method is to iterate through all elements, use window.getComputedStyle() to read the zIndex, and parse the value, ignoring NaN results.
  • A for...of loop provides a clear and readable implementation of this logic.
  • Be mindful of the performance implications on very large and complex pages, although for most use cases, the approach is perfectly acceptable.

By using this technique, you can reliably ensure that your dynamically created elements always appear on top of existing content.