setDragImage Edge Cases
What this is
The HTML Drag and Drop API is an important tool for building dynamic interfaces, but it is inconsistently implemented across browsers (which can be quite frustrating). The goal of this post is to enumerate some of these rough edges, specifically with regards to the
setDragImage method on the
Firefox and the DOM
When using a custom element for the drag image, Firefox prefers it to be in the DOM. In fact, it won’t display it otherwise. Safari and Chrome permit this, but they don’t like it. They’ll often pick up weird artifacts in the drag image from nearby elements.
Unfortunately, there isn’t a good way to test for this other than looking at the browser’s user agent2:
It works like this, on
dragstart add the element to the DOM for Firefox:
dragend clean-up the drag image:
Using an image
To use an image (or background image) for the drag image, it must first be downloaded. Otherwise the drag image appears blank on drag. Images can be prefetched using an image element:
Also worth noting, animated gifs do not animate when set as the drag image.
Positioning the drag image
The latter two arguments for
setDragImage are the x and y offset of the drag image relative to the cursor. Often examples set these to a specific number like
0, but this differs from the normal
img drag behavior which sets the drag image relative to the cursor position on mousedown.
To recreate this behavior, use
getBoundingClientRect() to calculate the offset position:
Maximum drag image dimensions
Anecdotally these are the largest pixel dimensions for a drag image before cropping occurs:
400×400 - Safari/Chrome
700×450 - Firefox
Noting this, it is important to scale the dimension of the drag image as well as its offset position. The following scales the
clientRect to the smallest maximum:
Firefox and window.devicePixelRatio
Unlike Safari and Chrome, Firefox sees the actual dimensions not the retina-scaled dimensions. Multiply the offsets by the
devicePixelRatio, otherwise Firefox’s offset is always off on retina screens3:
Firefox and the drag event
Safari and Chrome provide dynamic mouse position on the
drag event. Firefox does not (wontfix). To get around this just use the
dragover event which provides the mouse position in all browsers.
- Firefox will not allow you to drag an element without the
- The drag image element accepts limited styling.
setDragImageis used to set a custom ghosted image that appears while a
draggableelement is being dragged. This post glosses over the basics of its usage, which is covered quite thoroughly in Setting a custom ghost image when using HTML5 drag and drop. ↩
It would better to have a feature test for this. I’m open to suggestions. ↩
Again, open to suggestions for feature detection in lieu of user agent detection. ↩