The relationship between these two properties seems to have been the source of some confusion. Based on reading both the MDN site and MSDN I thought I had figured it out, but now I am not sure...
I figured that when an element is dragged, you can specify what is allowed to happen to it (i.e. it can be moved, copied, linked to - one of the effectAllowed
constants). This is the effectAllowed
property.
Different drop targets do different things, so when you drag over another element it can control which "effect" takes place on the drop, this is the dropEffect
property. So I set up a simple example to test this theory out:
JSFiddle
$("[draggable='true']").on("dragstart", function(e) {
var dt = e.originalEvent.dataTransfer;
dt.effectAllowed = "copyMove";
dt.setData("text/plain", "Foo");
});
$("#dropZoneCopy").on("dragover", function(e) {
var dt = e.originalEvent.dataTransfer;
dt.dropEffect = "copy";
e.preventDefault();
});
$("#dropZoneMove").on("dragover", function(e) {
var dt = e.originalEvent.dataTransfer;
dt.dropEffect = "move";
e.preventDefault();
});
I have a box the user can drag - the effects allowed are copyMove
. I have one box that sets dropEffect
to copy, and once that sets dropEffect
to move. What I expect is that when the user drags over the "copy box" the cursor will change to indicate a copy will happen, as I drag over the "move box" the cursor changes to indicate a move...
Only Chrome behaves as I would expect. Is this because the other browsers are wrong or because I don't understand the spec. properly ?
UPDATE Some more information from fiddling with this;
In both Firefox and Chrome, if you have a drag source which indicates the effectAllowed
is copy
and a drop zone that says dropEffect
is move
then you cannot drop on the drop zone even if you cancel the event. I thought that dropEffect
would be useful to read ondrop to see what to do, but it isn't available on Chrome, the dropEffect
does not appear on the drop handler, e.g. trying to read the dataTransfer.dropEffect
will say that the dropEffect
is none
even though you set it on dragover. Setting the dropEffect
as noted above does influence the way the cursor is displayed.
On Firefox, the dropEffect
does come through on the dropzone after being set on dragover, but it does not influence the display of the mouse cursor. On Firefox on Windows pressing the Ctrl key does affect the display of the mouse, but does not affect the dropEffect
property.
The spec shows that the source can listen for the dragend event to see what happened. It should look at the dropEffect
within this event. Chrome, Mozilla and Safari work as you would hope here, the drop effect appears in the dragend event. In IE if the effect allowed is a simple value e.g. "copy" then any successful drop results in this value appearing as the dropEffect on dragend. If the effectAllowed was a compound value like copyMove and you tried to select "move" on dragover by setting the dropEffect, you're out of luck, that will come through as dropEffect = "none" at the source on dragend. You are stuck with one cursor & one dropEffect and that is the effectAllowed set on dragstart if that effect is a simple value. Interestingly the dropEffect it seems does come through when you drag into a native application from IE11 at least (and i assume earlier).
Other notes
On Safari on a Mac - effectAllowed
cannot be set programatically, therefore any dropEffect that gets set is valid. When you press the cmd key the effectAllowed becomes "move" and when you press the alt key the effectAllowed becomes "copy". Thereafter it works as you would hope, if the dropEffect is not one of these effectAlloweds the drop is not allowed by the browser.
More Info I've been spending some spare time working on an HTML5 drag and drop library I wrote a bunch more about this and other issues in the docs for it, if you're interested please take a look at the project
The relationship between these two properties seems to have been the source of some confusion. Based on reading both the MDN site and MSDN I thought I had figured it out, but now I am not sure...
I figured that when an element is dragged, you can specify what is allowed to happen to it (i.e. it can be moved, copied, linked to - one of the effectAllowed
constants). This is the effectAllowed
property.
Different drop targets do different things, so when you drag over another element it can control which "effect" takes place on the drop, this is the dropEffect
property. So I set up a simple example to test this theory out:
JSFiddle
$("[draggable='true']").on("dragstart", function(e) {
var dt = e.originalEvent.dataTransfer;
dt.effectAllowed = "copyMove";
dt.setData("text/plain", "Foo");
});
$("#dropZoneCopy").on("dragover", function(e) {
var dt = e.originalEvent.dataTransfer;
dt.dropEffect = "copy";
e.preventDefault();
});
$("#dropZoneMove").on("dragover", function(e) {
var dt = e.originalEvent.dataTransfer;
dt.dropEffect = "move";
e.preventDefault();
});
I have a box the user can drag - the effects allowed are copyMove
. I have one box that sets dropEffect
to copy, and once that sets dropEffect
to move. What I expect is that when the user drags over the "copy box" the cursor will change to indicate a copy will happen, as I drag over the "move box" the cursor changes to indicate a move...
Only Chrome behaves as I would expect. Is this because the other browsers are wrong or because I don't understand the spec. properly ?
UPDATE Some more information from fiddling with this;
In both Firefox and Chrome, if you have a drag source which indicates the effectAllowed
is copy
and a drop zone that says dropEffect
is move
then you cannot drop on the drop zone even if you cancel the event. I thought that dropEffect
would be useful to read ondrop to see what to do, but it isn't available on Chrome, the dropEffect
does not appear on the drop handler, e.g. trying to read the dataTransfer.dropEffect
will say that the dropEffect
is none
even though you set it on dragover. Setting the dropEffect
as noted above does influence the way the cursor is displayed.
On Firefox, the dropEffect
does come through on the dropzone after being set on dragover, but it does not influence the display of the mouse cursor. On Firefox on Windows pressing the Ctrl key does affect the display of the mouse, but does not affect the dropEffect
property.
The spec shows that the source can listen for the dragend event to see what happened. It should look at the dropEffect
within this event. Chrome, Mozilla and Safari work as you would hope here, the drop effect appears in the dragend event. In IE if the effect allowed is a simple value e.g. "copy" then any successful drop results in this value appearing as the dropEffect on dragend. If the effectAllowed was a compound value like copyMove and you tried to select "move" on dragover by setting the dropEffect, you're out of luck, that will come through as dropEffect = "none" at the source on dragend. You are stuck with one cursor & one dropEffect and that is the effectAllowed set on dragstart if that effect is a simple value. Interestingly the dropEffect it seems does come through when you drag into a native application from IE11 at least (and i assume earlier).
Other notes
On Safari on a Mac - effectAllowed
cannot be set programatically, therefore any dropEffect that gets set is valid. When you press the cmd key the effectAllowed becomes "move" and when you press the alt key the effectAllowed becomes "copy". Thereafter it works as you would hope, if the dropEffect is not one of these effectAlloweds the drop is not allowed by the browser.
More Info I've been spending some spare time working on an HTML5 drag and drop library I wrote a bunch more about this and other issues in the docs for it, if you're interested please take a look at the project
Share Improve this question edited Jan 23 at 8:39 user5127 15911 bronze badges asked Dec 9, 2013 at 12:58 WoodyWoody 8,0022 gold badges23 silver badges25 bronze badges 2- 3 Your understanding of the spec is fine, the browser support is lacking. See the answers here for some alternatives: stackoverflow.com/q/24000954/2126792 – pschueller Commented Jun 11, 2014 at 23:10
- The spec/implementation seems very disappointing. As far as I can tell dataTransfer.dropEffect is of no use in a 'drop' event... – mpr Commented Apr 13, 2023 at 22:12
2 Answers
Reset to default 1You set effectAllowed
on the drag source (dragstart) to set what actions are allowed (like copy
, move
, or copyMove
).
dropEffect
gets set on the drop target (dragover) which sets what happens when you drop (like copy
or move
).
The catch here is that dropEffect
has to match one of the effectAllowed
values otherwise the drop won't work.
Your setup is fine.
You set effectAllowed
to copyMove
on the draggable.
The copy box sets dropEffect
to copy
.
The move box sets dropEffect
to move
.
You expect:
Dragging over the first box should show the copy cursor.
Dragging over the second box should show the move cursor.
What happens:
- Chrome: Works as you’d expect. The cursor changes based on the dropEffect.
- Firefox: The
dropEffect
works (you can see it in thedrop
event) but the cursor doesn’t update visually. - Safari: You can’t programmatically set
effectAllowed
. Instead, it’s determined by modifier keys:- Alt: Copy
- Cmd: Move
- IE11:
- If
effectAllowed
is simple (likecopy
), it works fine. - If it’s compound (like
copyMove
),dropEffect
often gets ignored, and you’re left withdropEffect
set tonone
.
- If
So you can:
- Stick to one allowed effect (
copy
ormove
) for better cross-browser consistency. - Use CSS or overlays to visually indicate what’s happening, since browsers don’t always update the cursor properly.
- For Firefox you can tell users to hold the Ctrl key if they need the
copy
cursor as a fallback.
take a look at https://web.dev/drag-and-drop/
function handleDrop(e) {
e.stopPropagation(); // Stops some browsers from redirecting.
e.preventDefault();
var files = e.dataTransfer.files;
for (var i = 0, f; f = files[i]; i++) {
// Read the File objects in this FileList.
}
}