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