Docking boxes (dbx)

Version 3.0 — 26th March 2009

Docking boxes (dbx) adds animated drag 'n' drop, snap-to-grid, and show/hide-contents functionality to any group of elements.

And how could I resist re-creating one of the most iconic interfaces of modern times to show it off!

The script can work with rows, columns, or two-dimensional grids of objects, of any size and shape. And as you've come to expect from brothercake, all the functionality is fully accessible to the keyboard.

First released in March 2006, dbx2 was the first implementation of keyboard-accessible drag 'n' drop ever developed, and remains one of the most robust and elegant solutions on the web.  (cool)

Version 3 has been more than two years in development, and includes a whole raft of new features, improvements to existing features, and bugfixes from the previous version (2.05). See the Latest update section below for a complete rundown of what's new.

Calendar Mail Remote Contacts Videos Photos Notes Calculator Clock Weather Maps Stocks YouTube Camera AppStore Settings
Phone Text Safari Music

More demos

Here's a clutch of demos to highlight the major features, and suggest some ideas for possible applications. You can also download these demos individually:

The navigation boxes demo is the one that's included in the default download zipfile.

Get the script

Download the zipfile [70K] and unzip it into your site directory.

There are two main includes to put in the <head> section of your page — the main dbx script, and the stylesheet:

<!-- Docking boxes (dbx) by brothercake - -->
<script type="text/javascript" src="dbx.js"></script>

<!-- dbx stylesheet -->
<link rel="stylesheet" type="text/css" href="dbx.css" media="screen, projection" />

Then if you're using either the rules engine or the remote controls, you will also need to include the relevant codebase in the <head> section; it can go anywhere after the main dbx.js script:

<!-- dbx rules engine -->
<script type="text/javascript" src="dbx.rules.js"></script>

<!-- dbx remote controls -->
<script type="text/javascript" src="dbx.remotes.js"></script>

Finally, there's a single script include that should go at the very end of the <body> section, which is the dbx configuration script:

<!-- dbx configuration script -->
<script type="text/javascript" src="dbx-key.js"></script>

The configuration script contains the object constructors that configure and initialize the dbx manager, and each of the dbx groups you're using. Putting it at the end of the body is the preferred method, because this avoids the need to use any kind of load wrapper. This consequently also avoids the possibility of a flash of unsorted content, that might otherwise occur in some browsers (the momentary appearance of the boxes in their original order, before any cookie state is applied).

dbx works in the following or later browser versions: Opera 8, Firefox 2, Safari 2, Chrome, Konqueror 3, and Internet Explorer 6. To put this another way, it works in all browsers that support XMLHttpRequest.

If scripting (or this script) is not supported, you'll get the same HTML and CSS layout, but without dynamic behaviors.

The codebase scripts are all compressed (stripped of comments and uneccesary whitespace) so that they load and process faster. The zipfile also includes fully spaced and commented versions, for your interest and reference, and in case you want to do any hacking. I would however discourage you from hacking the main scripts, and encourage you to look at the API for any additional or modified behaviors you want. Editing the core scripts will make future upgrades far more difficult to implement.

dbx manual

The basic setup process is broken down into four steps:

  1. Setting up the HTML
  2. Writing the CSS framework
  3. Implementing the script
  4. Accessibility notes

More advanced development is covered in additional documentation:

  1. API events
  2. Remote controls
  3. The rules engine

Latest update

New features in v3.0:

  • The script now supports two-dimensional movement, along horizontal, vertical and diagonal axes. This new orientation can be further broken down into different movement and insertion modes:
    • boxes can be sorted continually (freeform mode) or not until the mouse is released [or the enter key is pressed, for keyboard users] (confirm mode)
    • a box and its target can be swapped over (swap mode), or one inserted before or after another (insert mode)
  • A sophisticated, dynamic rules engine that controls what movement is allowed, using a token-based syntax for defining distances and shapes. This is intended for gaming applications, and allows you to specify things like boxes only moving up or down, or only along a diagonal, or only in a triangular pattern like the movement of a knight in chess. This is implemented using two new API methods: group.setRule() and group.removeRule(). And is accompanied by a new API event: manager.onruletest (which fires whenever a rule is tested)
  • You can now have dynamic groups, ie. the number of boxes can vary between and during a session, which means that you can implement groups for which the content is unknown, or where boxes can be added and removed using Ajax. This is controlled using another new API method: group.refresh()
  • Boxes can now be remotely controlled, using another four new API methods: group.move() (for moving an object in a specific direction), group.swap() (for swapping two boxes), group.insert() (for inserting one box before or after another), and group.toggle() (for opening or closing a box)
  • There's a further three new API events: manager.onanimate (which fires continually as box animation occurs, so you can tie it into other processes), manager.onafteranimate (which fires immediately after an animation is complete, for synchronising other things to what is otherwise an asynchronous process), and manager.onbeforestatechange (which fires just before onstatechange, so you can control it more precisely)

Bugfixes and other improvements:

  • confirmed support for contemporary browser releases: Opera 9, IE7, IE8, Chrome, Firefox 3, Safari 3, Safari 4, Konqueror 4
  • full support for konqueror 3.4 or later; partial support for konqueror 3.2–3.3 — boxes can be opened and closed, but not moved
  • no conflict with spatial navigation in Opera; in fact spatial navigation is now the best way to interact with it, since you can move between targets using Shift + Arrow and then move them using Arrow
  • a range of new dynamic and/or state-dependent class names:
    • "dbx-box-focus" (applied to a box when the handle or anchor has the keyboard focus)
    • "dbx-box-hover" (applied to a box when the mouse is over its handle or anchor)
    • "dbx-box-active" (applied to a box when the mouse or key is down on the handle or anchor)
    • "dbx-dragclone" (a clone being dragged with the mouse, in addition to the "dbx-clone" class name)
    • "dbx-aniclone" (an animation clone, in addition to the "dbx-clone" class name)
    • "first-child" and "last-child" (the boxes which are currently at the beginning and end of their group, respectively)
  • toggle buttons / anchors can now be <button> elements instead of <a> elements, which means cleaner output (no junk hrefs) and potentially better semantics (hence better usability to assistive devices)
  • an expanded range of references available in all API functions
  • improved validation and automatic error-correction in object constructors
  • refined onboxdrag behaviors, so it only fires from keyboard actions when a target actually exists
  • full default action suppression in Opera (as of v9)
  • removed support for Opera 7.5 and Safari 1.2, for the sake of leaner and more efficient code, because these older versions are now little used, if at all
  • a reduced cookie footprint, by rationalizing the state-string format — it now only stores "-" for closed and otherwise assumes open; but the cookie parser is still backwardly compatible with the previous format

How it works

The real trick here is that the underlying elements don't move — what you're holding when you drag with the mouse, and what you see moving when animation occurs, is just a temporary clone.

The original box is still there, invisible until the drag or animation is complete, at which point the node order is updated for real, the clone destroyed, and the original box made visible once again  (smile)

This approach worked out significantly cleaner and simpler than restyling the original boxes and creating place-holders in their wake. But more importantly, it means the script can work off elements with float or relative positioning, and having scaleable or fluid widths.

Implementing keyboard accessible drag 'n' drop (which I've dubbed press 'n' push) was actually pretty simple — the processes of re-ordering the boxes, and the visual transitions that go with them, were already abstracted into methods; so all I needed was a focusable element to act as anchor, with a key handler to determine the action and pass the relevant data to those methods. Well, it wasn't quite as simple as that, but essentially it was. My point is that making this functionality accessible to the keyboard was not desperately difficult, and this is true for extending keyboard accessibility to scripted components in general. It's not rocket science, it just takes a little effort and motivation.

Get the script

BSD License → Terms of use

Version 3.5 Coming Soon

dbx3.5 adds support for touch events, so it works on the iPad and other touch devices.

It's not quite ready for release yet as it hasn't been extensively tested, but if you'd like to play around with the first beta, you can grab that here:

BSD License → Terms of use


Website gadgets

Bits of site functionality:

  • Docking boxes (dbx) [this page]

Usability widgets

Local network apps

Web-applications for your home or office network:

Game and novelties

Our internal search engine is currently offline, undergoing some configuration changes in preparation for a major site overhaul. In the meantime, you can still search this site using Google Custom Search.

In this area

Main areas

[brothercake] a round peg in a square hole, that still fits