The HTML5 drag and drop disaster

After spending about a day and a half in testing I am forced to conclude that the HTML5 drag and drop module is not just a disaster, it’s a fucking disaster.

The module should be removed from the HTML5 specification straight away, and conforming browsers should disable it at their earliest opportunity pending a complete rewrite from the ground up.

Web developers MUST NOT (in the sense of RFC 2119) use HTML 5 drag and drop. They should use old-school scripts instead.

Before we continue I’d like to say that in general I thoroughly approve of the HTML5 specification. Exactly because the spec has such an overall quality I was so surprised (and, frankly, a bit confused and hurt) to find drag and drop a steaming pile of bovine manure.

In fact, it’s so outrageously bad that I’ve gone on strike. I refuse to do any more research on drag and drop. Go do it yourself. Or don’t bother. Whatever. I don’t care.

What follows is a rant laced with profanity. No apologies. Drag and drop deserves no better.

Who got us into this mess?

Microsoft “designed” and implemented drag and drop way back in 1999, when IE 5.0 was released. IE versions has supported it ever since.

This specification was terribly bad, as we’ll see in a moment. Microsoft dropped the ball majorly here.

Still, while Microsoft is to blame initially, the HTML5 WG and the other browser vendors are accessories to the crime.

One of the guiding principles of HTML5 and its WHAT-WG precursors is to document everything that already works in browsers but previous Working Groups couldn’t be arsed to specify, such as innerHTML and offsetWidth .

Although I thoroughly support that principle and see how it applies to the Microsoft drag and drop module, I still think that some form of critical reflection might have been in order in this particular case.

Hixie said:

The drag-and-drop API is horrible, but it has one thing going for it: IE6 implements it, as do Safari and Firefox.

Now that is undeniably true. God knows why, but Firefox, Safari, and Chrome have shoveled it straight into their rendering engines, and critical reflection be damned. Only Opera has retained its sanity.

Interoperability is very important. But not at any price. The price is too high when it comes to drag and drop.

The transcript of my testing sessions

OK, so what exactly is wrong with the HTML5 drag and drop module?

I’ll show you.

Below follows an approximate transcript of my testing sessions. It shows you what I went through and why I wrote this entry.

This was an exceptionally bad case. The worst I’ve encountered since the demise of Netscape 4, in fact. That’s why the transcript includes profanity. Lots and lots of profanity.

Too many events

There are no less than seven events associated with drag and drop: dragstart, drag, dragover, dragenter, dragleave, drop, and dragend.

This seems rather a lot for a series of actions that can be accurately described by the mousedown, mousemove, and mouseup events.

In itself that’s not a disaster, just bad API design. We have to pick a few events and ignore the rest.

[ ... tinker ... ]

[ ... tinker ... ]

Say. Fucking. WHAT?!?

The drop event fires when the user drops an element he’s dragging.

And, you see, dropping the element you’re dragging is the POINT of this entire module.

So drop is the most important event. But it doesn’t fire. Let’s see ...

[ ... tinker ... ]

[ ... consult spec and example ... ]

OK, got it.

For the drop event to fire at all, you have to cancel the defaults of both the dragover and the dragenter event.

[ ... ]

... say WHAT?!?

OK, let’s try again:

The default action of the dragover and the dragenter events is NOT being able to drop an element. And you have to cancel these default actions in order to drop an element. Obviously.

[ ... ]

Say. Fucking. WHAT?!?

OK, one more time:

The dragover and dragenter events exist for the sole reason of forcing web developers who want to perform a drop action to cancel their obscure default actions.

You’re kidding me.

[ ... crickets ... ]

You’ve GOT to be FUCKING kidding me!

I’m not going to cancel the default actions of not one but two of your bullshit events in order to get the most important action in the entire fucking module working.

Then we won’t play. Nyaa, nyaa...

You bunch of fucking idiots don’t have the fuckingest clue what you’re doing!

[ ... crickets ... ]

Now listen carefully, and you might actually learn something:

Default actions are supposed to be defined in positive terms: if you take this action, that will happen, unless the script cancels it. That’s how JavaScript events were designed to work.

[ ... crickets ... ]

No wonder I can’t give up smoking.

[ ... drag ... ]

Calm down, calm down. Let it be. Maybe it’ll go away by itself.

Do something else first.

Return to normalcy

When I defined a dragstart event handler, the other events just stopped firing in IE. All of them.

When I studied Remy Sharp’s test case, however, I found it works in IE8 despite the presence of the dragstart event.

This is a strange inconsistency, especially since the spec is supposed to be based on the IE implementation. So either the spec has overlooked a special case in which all the other events are canceled, or IE sometimes doesn’t implement its own implementation.

I’m guessing the latter right now. Browser bug #1. To be retested, ascertained, and documented.

Phew, finally something normal.

Maybe the ... other thing ... will turn out not so bad, after all.

But first some more events.

dragthis

The drag event is like mousemove, except that it fires during a drag operation. Hey, this makes sense! Works everywhere? Yup. Next.

dragthat and dragsomethingelse

In theory dragenter and dragleave could be great events, since they fire when you enter or leave an HTML element in the middle of a drag operation. If that element is a valid drop target you could change its styles ondragenter and ondragleave to indicate this fact to the user.

With the spec being based on the Microsoft API, I expected dragenter and dragleave to emulate mouseenter and mouseleave. But they didn’t. Not even in IE. They’re based on mouseover and mouseout and suck every bit as badly. And their names are wrong.

Mouseover and mouseout are terrible because they bubble up all the time and make it very hard to distinguish important events from unimportant ones. If I mouse over (or drag enter) a child element of the one that the event is set on, it also fires. And that’s exactly what we don’t want. The events will fire incessantly the whole time the mouse is above the element, and we have to work hard in order to distinguish useful events from useless ones.

Mouseenter and mouseleave, on the other hand, fire only when you enter and leave the element they’re defined on, and they don’t bubble. That makes them much easier to use.

They are Microsoft extensions, by the way, and excellent ones at that. They work only in IE.

Note that originally mouseenter and mouseleave had exactly the same IE only compatibility pattern as drag and drop. Mouseenter and mouseleave are a good idea, drag and drop ... isn’t. Guess what the other browsers chose to implement?

No wonder web development is such a fucking pain with fucking morons in charge of the browsers.

Wait, that could be construed as an insult to morons.

Ah, what the fuck.

dragbullshit

Dragover, now, has nothing to do with mouseover. It’s exactly the same as the drag event, except that you can set it on any element instead of just the document. Or something. Whatever.

Why do we need the dragover event if we already have the drag event?

[ ... fume ... ]

To cancel its default action!

If we didn’t have to cancel its default action the dragbullshit event would have no fucking point!

And we can’t have pointless events in our nice specification, now, can we?

So we give it a default action. A very complicated default action.

That has to be canceled. Absolutely, positively has to be canceled.

[ ... crickets ... ]

Anybody LISTENING to what I say?

[ ... drag ... ]

I deserve a fucking MEDAL for this. Above and beyond the call of fucking DUTY.

draggable

Then we have the draggable attribute that, when set to true , allows an element to be dragged. It only works in Firefox. Links and images are draggable by default.

Actually that’s a pretty good idea.

Wow, I can finally say something nice. But to whom?

I’m assuming that draggable is an HTML5 addition because it doesn’t work in IE, and therefore I’m assuming I can congratulate the HTML5 WG with having had a good idea.

You see, I can’t find the Microsoft documentation on drag and drop, so I can’t check whether draggable is supposed to be supported in IE.

In practice it isn’t, that’s for sure.

(If you know where to find the Microsoft documentation, don’t bother leaving a comment. Meanwhile I don’t care any more.)

Safari fuckup

Next problem.

In order to get drag and drop working in Safari, add this to your CSS!

#tobedragged { -khtml-user-drag: element; }

[ ... ]

Q: Hi, how do you want me to present this element to the user?

A: It’s draggable.

[ ... ]

Fuck you, Safari team. Fuck. You.

Wait, let’s rephrase that. A gentle question might help more than a rant.

Dear Safari team, does “separation of presentation and behaviour” mean anything to you?

[ ... crickets ... ]

Thought not.

[ ... drag ... ]

Fuck you anyway.

Drop effects? Or drag effects?

The dropEffect property might actually set the drag effect. At least, that’s how I read the spec right now.

I could be wrong here. I have no fucking clue what a drag (or drop) effect is, and you don’t, either.

As an experiment I set the property to every single value the spec allows, and it made no difference whatsoever in any browser.

Then I discovered I had to set effectsAllowed to all in order to decree that all drop effects (which really may be drag effects) are allowed. This made no difference, either — no browser reacted to my setting of dropEffect by showing any of the now-allowed drag (or drop?) effects.

Some browsers report the value of effectsAllowed as copyLink , by the way. Just after I set it to all . A little creativity to show their good spirits, I presume.

And why would I need to give permission at all? Setting dropEffect to the desired value indicates that I command (and, by implication, permit) the effect to take place.

Doesn’t it?

[ ... crickets ... ]

[ ... crickets ... ]

Oh, fuck you. I give up.

Strike

If you’re still not convinced that drag and drop sucks, read Francisco Tolmasky’s article on bugs and problems he encountered.

In fact, from his piece it almost seems as if the browser vendors have trouble implementing drag and drop.

Gee, I wonder why that is.

But I’m not going to figure it out. I’ve had enough.

Any unanswered questions you might have after reading this piece will remain unanswered for all eternity, as far as I’m concerned. I don’t see why I should spend another two to three (unpaid) days on this pile of junk.

Go do your own research for a change.

And don’t bother leaving pointers to useful articles and stuff. I just don’t care any more, and I’m certainly not going to read them.

I’m on strike.

Comments are closed.