Contact   •   Products   •   Search

Rick Strahl's Web Log

Wind, waves, code and everything in between...
ASP.NET • C# • HTML5 • JavaScript • AngularJs

Getting and setting max zIndex with jQuery


I have a fair number of applications that use pop up windows and other draggable elements  that are stackable. When dragging and moving windows around the page it’s often critical to ensure that windows show up in the proper zOrder without having to explicitly assign the window order.

A typical scenario for this is dragging multiple windows like this:

 OverlappingWindows

When you drag one window that window should pop to the top of the zOrder and stay there once the window is dropped. The idea is that as windows are dragged the zIndex keeps getting re-arranged in such a way that the last dropped window/element ends up on top of the zIndex stack. You can try this out online here. If you use Add two windows are open – move them around to see how this works. Also notice that the List window always pops on top when Add is clicked and this is where the zIndex plugin discussed below comes in.

A long time ago (prior to jQuery Ui) I built my own draggable plug-in and one of the main things it did is upon dropping it would elevate the zIndex up by a few tick which was crucial. While that worked it was still guess work trying to find a zIndex that wasn’t already taken up by some other component but it worked more or less. At the time I allowed specification of a zIndex value for the dragged window and the component would bump that for each window dragged. 

jQuery' Ui’s draggable initially didn’t have this feature (which was annoying), but it’s been added in later iterations as well using the stack option parameter. My lightweight version and jQuery ui version are fairly compatible so if the jQuery Ui one is loaded that will be used and both understand and use the stacking feature.

To set up stacked dragging using jQuery Ui and the draggable plug-in you might do something like this on all ‘dialogs’ (not jQuery.ui Dialogs):

$(document).ready(function() {
    var dialog = $(".dialog")
                    .draggable({opacity: .25,
                                cursor: "move",
                                stack: { group: "*", min: 50 },
                                handle: ".dialog-header"
                                })
                    .shadow()
                    .closable();
});

and that handles the zOrder  correctly without explicitly having to manipulate the z-index of any dragged elements. Surprisingly this isn’t the default behavior though.

However there are situations where you might have to manually force a window to the top. In my case I have several places where multiple windows are opened when a page is loaded or a button is clicked and they have to open in a specific stacking order. In order to accomplish this I have to force the windows to the top one at a time in the right order. Also internally in my framework there are a number of places where I definitely need to know the max zorder – for example for modal dialogs which should pop on top whatever content is on the page regardless of what their zIndex.

A small maxZIndex Plug-in

After having written some code to do this a few times I created a small plug-in that handles both finding the max zIndex and incrementing it by a specific value on the selected element(s). The latter is probably the more common case – it’s rare that you need to know the highest zOrder but don’t actually need to set it.

Anyway here’s the code that implements the plug-in and utility function in one implementation:

$.maxZIndex = $.fn.maxZIndex = function(opt) {
    /// <summary>
    /// Returns the max zOrder in the document (no parameter)
    /// Sets max zOrder by passing a non-zero number
    /// which gets added to the highest zOrder.
    /// </summary>    
    /// <param name="opt" type="object">
    /// inc: increment value, 
    /// group: selector for zIndex elements to find max for
    /// </param>
    /// <returns type="jQuery" />
    var def = { inc: 10, group: "*" };
    $.extend(def, opt);    
    var zmax = 0;
    $(def.group).each(function() {
        var cur = parseInt($(this).css('z-index'));
        zmax = cur > zmax ? cur : zmax;
    });
    if (!this.jquery)
        return zmax;

    return this.each(function() {
        zmax += def.inc;
        $(this).css("z-index", zmax);
    });
}

To use it I can do something like this:

function DoToTop() {
    // Set the zIndex to max + 5
    $("#divDialog").maxZIndex({ inc: 5 });
    
    // Get the zIndex as a number
    alert($.maxZIndex());
}

The first jQuery wrapped set function finds the max zIndex value and increases it by 5 on the divDialog element. If I use the utility function $.maxZIndex() I get the value returned instead. IOW, the utility function returns a value, the plug-in sets the value.

This plug-in and utility function setup may seem like an odd choice but I did want the option of not passing a parameter to the plug-in function that sets the zIndex. So doing just:

$("#divDialog").maxZIndex();

also sets the maxZIndex() with the default values – ie. incremented by 10. Why the increment?  Often you want to inject other elements later for example a modal dialog is displayed first and the modal background added later with a lower zIndex and using an increment value allows for a little space to add additional elements if necessary.

The option parameter to the plug-in has two configuration values:

inc
The value to increment the max zOrder found in the specified group of elements. Defaults to 10.

group

A selector of elements that are searched for finding the max zIndex value. Defaults to “*”

Very simple, but highly useful at least in my code. I’ve been able to throw out a ton of z-index related code in various of my own plug-ins which is sweet. Maybe some of you might find this useful as well.

Resources

If you want to check out the sample shown above you can grab it from the West Wind West Wind Web Toolkit repository.

West Wind Web Toolkit Source and Examples

Make Donation


Feedback for this Post

 
# re: Getting and setting max zIndex with jQuery
by jim August 31, 2009 @ 7:38am
I tried the sample of the Amazon book selection. Not clear if this new jQuery is included or not...but if it is, you need to take another look at what results I saw. I'll send you the screen shot off line.

In the mean time, can you post a comment about adding this to the existing version of WC? I would like to use it with my modal dialog that pops a calendar control. Although I have it working by manually setting it, it would be great to move in this direction.

good article...<g>
# re: Getting and setting max zIndex with jQuery
by Rick Strahl August 31, 2009 @ 11:55am
@Jim - actually the list display is a bug in jQuery.ui.sortable. I noticed this late yesterday and it's caused by the sortable manipulating the zIndex. Especially a problem in IE.

Anyway I fixed this by setting an initially high z-index on the windows so they always end up above the sortable.

But this actually just makes my point <s> - this is caused by jQuery UI because they DON'T move the z-index predictably. It appears they're setting it to a fixed value and leaving it, which is interfering with the rest of the page that has other items on top of it. Looks like this behavior is new in jQuery.ui 1.7.2 - never saw this before.

IAC, it appears to work now.

As to WC yes the plug-in will be part of ww.jquery.js or you can just add it in there yourself now in the current version.
# re: Getting and setting max zIndex with jQuery
by andrew September 01, 2009 @ 1:05am
Why do you use .shadow() ? This component is no longer part of jQuery UI.
# Getting and setting max zIndex with jQuery
by WebDevVote.com September 01, 2009 @ 8:33am
You are voted (great) - Trackback from WebDevVote.com
# re: Getting and setting max zIndex with jQuery
by Speednet September 01, 2009 @ 11:54am
Hi Rick,

Great idea! I've been doing something similar to this kicking around in code, but boiling it into a jQuery plugin is a great idea.

I was just about to use your code as-is when a bit of inspiration hit as to another way to do the same thing, except it uses a bit more native browser functionality -- so hopefully a little quicker.

I remember that if you ever need to get a minimum or maximum value from an array, you can use the apply() function to Math.min() or Math.max(), which is very quick. So I changed the code to use a simple $.map() function to get all the z-index values into an array, and then used apply.Math.max().

Then, by the time I finished tinkering with it, I had basically re-written the whole thing, so I went ahead and finished it off as a plugin and bumped it up to GoogleCode.

So here's the final product, with demo page. I linked back to this blog entry in the code comments, and renamed the plugin to respect your work here.

http://topzindex.googlecode.com/

The minified code (included) is only 374 bytes.

-Todd
# Getting and setting max zIndex with jQuery
by PimpThisBlog.com September 16, 2009 @ 12:39pm
Thank you for submitting this cool story - Trackback from PimpThisBlog.com
# re: Getting and setting max zIndex with jQuery
by Soichi Hayashi November 06, 2009 @ 7:58pm
Great! This fixed my issue.
# re: Getting and setting max zIndex with jQuery
by Mustapha kone November 20, 2009 @ 8:13am
greetings,

great and nice tool!
I assume that you can pass in a variable named "group" as part of the json variable "opt" being passed in.
# re: Getting and setting max zIndex with jQuery
by tony December 20, 2009 @ 5:13pm
great plugin, really useful. One minor thing I've found is that when very large numbers are used, jquery returns the z-index in scientific notation. This causes problems if you use parseInt directly, as everything seems to get parsed as 1. I found if you use:

var cur = parseInt(Number($(this).css('z-index')));

it seems to work in these situations.
 


West Wind  © Rick Strahl, West Wind Technologies, 2005 - 2014