Originally published at: http://www.sitepoint.com/accessible-drag-drop/
In this article, I’d like to show you how to extend the capabilities of HTML5 drag and drop — so it can handle multiple elements, and support keyboard interaction, for sighted and screen reader users.
I’m going to assume that you already have a passing familiarity with the drag and drop API, but if not, have a look at this introductory article (ignoring the references to Modernizr, which you won’t need).
The basic approach to dragging multiple elements is actually pretty trivial — we simply need to remember the drag data for more than one element. We could do that using the
dataTransfer object, or we can just use a separate array (which is what we’re going to do). So why write a whole article about it?
Why — because although the data is simple, the interface is rather more complex.
We’ll need to do some extra work to implement a pre-selection mechanism, and we’ll need to make it work from the keyboard (since native drag and drop doesn’t support this).
Note: This article won’t cover touch events, nor provide a polyfill for older browsers. Furthermore, the approach we take will only work within a single page, it won’t support dragging between windows. Although the drag and drop API does support this, there’s no straightforward way of making it keyboard accessible.
Basic Drag and Drop
So let’s start with a functional example which defines the basic drag and drop events, allowing a single element to be dragged with the mouse between two containers:
There’s a few things in there that might differ from other demos you’ve seen.
The first is the way it maintains an
item reference for the element being dragged, rather than passing the element’s
ID through the
dataTransfer object (although we do have to pass something or the whole operation will fail in Firefox; it could be anything, so an empty string will do):
var item = null;
item = e.target;
This simplifies the demo by avoiding the need for the elements to have IDs, and would make it much easier to extend into a server-side application (like a CMS), where element IDs may not be easily knowable. This approach will also be the basis of multiple selection, where the
item reference will become an
The next significant thing is the omission of the event properties,
dropEffect. These can take a value such as
"move", and are supposed to control which actions are allowed and which cursor the browser will show. However, browser implementation is inconsistent, so there’s not much point including them.
Finally, note how the underlying HTML does not include any
<li data-draggable="item">Item 0</li>
<li data-draggable="item">Item 1</li>
<li data-draggable="item">Item 2</li>
<li data-draggable="item">Item 3</li>
draggable attribute to browsers which pass feature detection.
This approach also provides the opportunity to exclude any broken implementations, for the cases where feature detection fails. Opera 12 or earlier is excluded using the
window.opera test, because its implementation is quite buggy, and it’s not worth spending time on anymore.
Accessible Drag and Drop
Accessibility is a fundamental design principle, and it’s always easier to it get right when considered in those terms. So before we go any further with this demo, we must have a clear idea of the requirements for keyboard and screen reader accessibility.
The ARIA Authoring Practices has a section on drag and drop, which outlines the attributes we’ll need, and has guidelines on how the interactions should work. To summarize:
- Draggable elements are identified with
aria-grabbed="false", and must be navigable with the keyboard.
- Provide a mechanism for the user to select which elements they want to drag, and the recommended keystroke is Space. When an element is selected for dragging, its
aria-grabbed attribute is set to
- Provide a mechanism for the user to indicate that they’ve finished making selections, and the recommended keystroke is
- Target elements are then identified with
aria-dropeffect, with a value that indicates which actions are allowed, such as
"copy". At this point in the process, target elements must also be navigable with the keyboard.
- When the user arrives at a target element, provide a mechanism for them to perform the drop action, and the recommended keystroke is also
- Users can cancel the entire operation at any time, by pressing the
- When the action is completed or aborted, clean-up the interface by setting all
aria-dropeffect attributes to
"none" (or removing them), and all
aria-grabbed attributes to
Now the two ARIA attributes,
aria-dropeffect, must be used according to specification. However, the events and interactions are simply recommendations, and we don’t have to follow them slavishly. Nonetheless, we should (and will) follow these recommendations as closely as possible, because they’re the closest thing we have to a normative reference.
And for the most part, I think it makes sense. But I do take issue with both uses of the
Control+M keystroke. I’m not convinced that it’s really necessary to have an end-of-selection keystroke at all, and I don’t the keystroke itself is very intuitive for sighted keyboard users.
So I think the best approach is to supplement those recommendations:
- We will implement the end-of-selection keystroke, but it won’t be required nor prevent further selection, it will simply be a shortcut for moving focus to the first drop target.
- We will use
Control+M for both keystrokes, but we’ll also allow the drop action to be triggered with the
The guidelines also talk about implementing multiple selection using modifiers. The recommendation is to use
Shift+Space for contiguous selection (i.e. selecting all items between two end points), and
Control+Space for non-contiguous selection (i.e. selecting arbitrary items). Those are clearly the best modifiers to use … however, the Mac equivalent of
Control+Space would be
So for the sake of simplicity, and to side-step this problem, we’re not going to implement contiguous selection. The simplest thing we can do for now is to support all three modifiers for non-contiguous selection — Command+Space, Control+Space or Shift+Space are all treated the same way on every platform — then whatever a particular user can trigger, and whatever they think makes sense, is available.
Continue reading this article on SitePoint