Drag Operations

  • Revision slug: DragDrop/Drag_Operations
  • Revision title: Drag Operations
  • Revision id: 328857
  • Created:
  • Creator: ndm250
  • Is current revision? No
  • Comment Small grammar error.

Revision Content

The following describes the steps that occur during a drag and drop operation.

The Draggable Attribute

Within a web page, there are certain cases where a default drag behaviour is used. These include text selections, images and links. When an image or link is dragged, the URL of the image or link is set as the drag data, and a drag begins. For other elements, they must be part of a selection in order for a default drag to occur. To see this in effect, select an area of a web page, and then click and hold the mouse and drag the selection. An OS-specific rendering of the selection will appear and follow the mouse pointer as the drag occurs. However, this behaviour is only the default drag behaviour, if no listeners adjust the data to be dragged.

In HTML, apart from the default behaviour for images, links and selections, no other elements are draggable by default. All XUL elements are also draggable. In order to make another HTML element draggable, two things must be done:

  • Set the draggable attribute to true on the element that you wish to make draggable.
  • Add a listener for the dragstart event and set the drag data within this listener.

Here is an example which allows a section of content to be dragged.

<div draggable="true" ondragstart="event.dataTransfer.setData('text/plain', 'This text may be dragged')">
  This text <strong>may</strong> be dragged.
</div>

The draggable attribute is set to true, so this element becomes draggable. If this attribute was omitted or set to false, the element would not be dragged and instead the text would be selected. The draggable may be used on any element, including images and links. However, for these last two, the default value is true, so you would generally only use the draggable attribute with a value of false to disable dragging of these elements.

Note that when an element is made draggable, text or other elements within it can no longer be selected in the normal way by clicking and dragging with the mouse. Instead, the user must hold down the Alt key to select text with the mouse, or use the keyboard.

For XUL elements, you do not need to use the draggable attribute, as all XUL elements are draggable.

<button label="Drag Me" ondragstart="event.dataTransfer.setData('text/plain', 'Drag Me Button');">

Starting a Drag Operation

In this example, a listener is added for the dragstart event by using the ondragstart attribute.

<div draggable="true" ondragstart="event.dataTransfer.setData('text/plain', 'This text may be dragged')">
  This text <strong>may</strong> be dragged.
</div>

When a user begins to drag, the dragstart event is fired. In this example the dragstart listener is added to the draggable element itself, however, you could listen to a higher ancestor as drag events bubble up as most other events do. Within the dragstart event, you can specify the drag data, the feedback image and the drag effects, all of which are described below. However, only the drag data is required; the default image and drag effects are suitable in many situations.

Drag Data

All drag events have a property called dataTransfer which is used to hold the drag data.

When a drag occurs, data must be associated with the drag which identifies what is being dragged. For example, when dragging the selected text within a textbox, the data associated with the drag is the text itself. Similarly, when dragging a link on a web page, the drag data is the URL of the link.

The drag data contains two pieces of information, the type, or format, or the data, and the data value. The format is a type string (such as text/plain for text data), and the value is a string of text. When the drag begins, you would add data by providing a type and the data. During the drag, in an event listener for the dragenter and dragover events, you would use the types of the data being dragged to check whether a drop is allowed. For instance, a drop target that accepts links would check for the link type text/uri-list. During a drop event, a listener would retrieve the data being dragged and insert it at the drop location.

Types are a MIME-type like string, such as text/plain or image/jpeg. You can also create your own types. The most commonly used types are listed at Drag Types.

A drag may provide data of several different types. This allows data to be provided in more specific types, often custom types, yet still provide fallback data for drop targets that do not support more specific types. It is usually always the case that the least specific type will be normal text data using the type text/plain. This data will be a simple textual representation.

To set data within the dataTransfer, use the setData method. It takes two arguments, the type of data, and the data value. For example:

event.dataTransfer.setData("text/plain", "Text to drag");

In this case, the data value is "Text to drag" and is of the format text/plain.

You can provide data in multiple formats. To do this, call the setData method multiple times with different formats. You should call it with formats in order from most specific to least specific.

var dt = event.dataTransfer;
dt.setData("application/x-bookmark", bookmarkString);
dt.setData("text/uri-list", "http://www.mozilla.org");
dt.setData("text/plain", "http://www.mozilla.org");

Here, data is added in three different types. The first type 'application/x-bookmark' is a custom type. Other applications won't support this type, but you can use a custom type for drags between areas of the same site or application. By providing data in other types as well, we can also support drags to other applications in less specific forms. The 'application/x-bookmark' type can provide data with more details for use within the application whereas the other types can include just a single URL or text version.

Note that both the text/uri-list and text/plain contain the same data in this example. This will often be true, but doesn't need to be the case.

If you attempt to add data twice with the same format, the new data will replace the old data, but in the same position within the list of types as the old data.

You can clear the data using the clearData method, which takes one argument, the type of the data to remove.

event.dataTransfer.clearData("text/uri-list");

The type argument to the clearData method is optional. If the type is not specified, the data associated with all types is removed. If no data is added to be dragged, or it is all subsequently cleared, then no drag will occur.

Setting the drag feedback image

When a drag occurs, an translucent image is generated from the drag target (the element the "dragstart" event is fired at), and follows the mouse pointer during the drag. This image is created automatically so you do not need to create it yourself. However, you can use the setDragImage() to specify a custom drag feedback image.

event.dataTransfer.setDragImage(image, xOffset, yOffset);

Three arguments are necessary. The first is a reference to an image. This reference will typically be to an image element but it can also be to a canvas or any other element. The feedback image will simply be generated from whatever the image looks like on screen, although for images, they will be drawn at their original size. It is also possible to use images and canvases that are not in a document, as in the following example:

function dragWithCustomImage(event) {
  var canvas = document.createElementNS("http://www.w3.org/1999/xhtml","canvas");
  canvas.width = canvas.height = 50;

  var ctx = canvas.getContext("2d");
  ctx.lineWidth = 4;
  ctx.moveTo(0, 0);
  ctx.lineTo(50, 50);
  ctx.moveTo(0, 50);
  ctx.lineTo(50, 0);
  ctx.stroke();

  var dt = event.dataTransfer;
  dt.setData('text/plain', 'Data to Drag');
  dt.setDragImage(canvas, 25, 25);
}

This technique is useful when drawing custom drag images using the canvas element.

The second and third arguments to the setDragImage() method are offsets where the image should appear relative to the mouse pointer. In this example, as the canvas is 50 pixels wide and 50 pixels high, we use offsets half of this (25 and 25) so that the image appears centered on the mouse pointer.

{{ h2_gecko_minversion("Using XUL panels as drag images", "9.0") }}

For Gecko developers (whether you're doing an add-on or Mozilla application code), Gecko 9.0 {{ geckoRelease("9.0") }} adds support for using a XUL {{ XULElem("panel") }} element as a drag feedback image. Simply pass your {{ XULElem("panel") }} element to the setDragImage() method.

Consider this XUL {{ XULElem("panel") }}:

<panel id="panel" style="opacity: 0.6">
  <description id="pb">Drag Me</description>
</panel>

<vbox align="start" style="border: 1px solid black;" ondragstart="startDrag(event)">
  <description>Drag Me</description>
</vbox>

When the user begins a drag by clicking and dragging from the {{ XULElem("vbox") }} above, the startDrag() function below is called.

function startDrag(event) {
  event.dataTransfer.setData("text/plain", "<strong>Body</strong>");
  event.dataTransfer.setDragImage(document.getElementById("panel"), 20, 20);
}

This uses the panel as the drag image, with the string "<strong>Body</strong>" as its data, in HTML format. Dropping the panel into a text editor results in the text "Body" being inserted into the text at the drop location.

Drag Effects

When dragging, there are several operations that may be performed. The copy operation is used to indicate that the data being dragged will be copied from its present location to the drop location. The move operation is used to indicate that the data being dragged will be moved, and the link operation is used to indicate that some form of relationship or connection will be created between the source and drop locations.

You can specify which of the three operations are allowed for a drag source, by setting the effectAllowed property within a dragstart event listener.

event.dataTransfer.effectAllowed = "copy";

In this example, only a copy is allowed. You can combine the values is various ways:

none
no operation is permitted
copy
copy only
move
move only
link
link only
copyMove
copy or move only
copyLink
copy or link only
linkMove
link or move only
all
copy, move, or link

Note that these values must be used exactly as listed above. If you don't change the effectAllowed property, then any operation is allowed, just like with the 'all' value. So you don't need to adjust this property unless you want to exclude specific types.

During a drag operation, a listener for the dragenter or dragover events can check the effectAllowed property to see which operations are permitted. A related property, dropEffect, should be set within one of these events to specify which single operation should be performed. Valid values for the dropEffect are none, copy, move or link. The combination values are not used for this property.

With the dragenter and dragover event, the dropEffect property is initialized to the effect that the user is requesting. The user can modify the desired effect by pressing modifier keys. Although the exact keys used vary by platform, typically the Shift and Control keys would be used to switch between copying, moving and linking. The mouse pointer will change to indicate which operation is desired, for instance, for a copy, the cursor might appear with a plus sign next to it.

You can modify both the effectAllowed and the dropEffect property during the dragenter or dragover events, if for example, a particular drop target only supports certain operations. Modifying the effectAllowed property lets you specify which set of operations are permitted at a certain drop target. For example, setting the effectAllowed property to copyMove allows a copy or move operation but prevents the user from performing a link operation.

You can modify the dropEffect property to override the user effect, and enforce a specific drop operation to occur. Note that this effect must be one listed within the effectAllowed property. Otherwise, it will be set to an alternate value that is allowed.

event.dataTransfer.effectAllowed = "copyMove";
event.dataTransfer.dropEffect = "copy";

In this example, copy is the effect that is performed as the specified effect is included in the list of allowed effects.

You can use the value none for either property to indiciate that no drop is allowed at this location.

Specifying Drop Targets

A listener for the dragenter and dragover events are used to indicate valid drop targets, that is, places where dragged items may be dropped. Most areas of a web page or application are not valid places to drop data. Thus, the default handling for these events is to not allow a drop.

If you want to allow a drop, you must prevent the default handling by cancelling the event. You can do this either by returning false from an attribute-defined event listener, or by calling the event's event.preventDefault method. The latter may be more feasible in a function defined in a separate script.

<div ondragover="return false">
<div ondragover="event.preventDefault()">

Calling the preventDefault method during both a dragenter and dragover event will indicate that a drop is allowed at that location. However, you will commonly wish to call the preventDefault method only in certain situations, for example, only if a link is being dragged. To do this, call a function which checks a condition and only cancels the event when the condition is met. If the condition is not met, don't cancel the event, and a drop will not occur there if the user releases the mouse button.

It is most common to accept or reject a drop based on the type of drag data in the data transfer. For instance, allowing images or links or both. To do this, you can check the types of the dataTransfer object. The types are a list of the string types that were added when the drag began, in the order from most significant to least significant.

function doDragOver(event)
{
  var isLink = event.dataTransfer.types.contains("text/uri-list");
  if (isLink)
    event.preventDefault();
}

In this example, we use the contains method to check if the type text/uri-list is present in the list of types. If it is, we will cancel the event so that a drop may be allowed. If the drag data does not contain a link, the event will not be cancelled and a drop cannot occur at that location.

You may also wish to set either the effectAllowed, dropEffect property, or both at the same time, if you wish to be more specific about the type of operation that will performed. Naturally, changing either property will have no effect if you do not cancel the event as well.

Drop Feedback

There are several ways in which you can indicate to the user that a drop is allowed at a certain location. The mouse pointer will update as necessary depending on the value of the dropEffect property. Although the exact appearance depends on the user's platform, typically a plus sign icon will appear for a 'copy' for example, and a 'cannot drop here' icon will appear when a drop is not allowed. This mouse pointer feedback is sufficient in many cases.

However, you can also update the user interface with an insertion point or highlight as needed. For simple highlighting, you can use the -moz-drag-over CSS pseudoclass on a drop target.

.droparea:-moz-drag-over {
  border: 1px solid black;
}

In this example, the element with the class droparea will receieve a 1 pixel black border while it is a valid drop target, that is, if the event.preventDefault method was called during the dragenter event. Note that you must cancel the dragenter event for this pseudoclass to apply, as this state is not checked for the dragover event.

For more complex visual effects, you can also perform other operations during the dragenter event, for example, by inserting an element at the location where the drop will occur. For example, this might be an insertion marker or an element that represents the dragged element in its new location. To do this, you could create an image or separator element for example, and simply insert it into the document during the dragenter event.

The dragover event will fire at the element the mouse is pointing at. Naturally, you may need to move the insertion marker around a dragover event as well. You can use the event's clientX and clientY properties as with other mouse events to determine the location of the mouse pointer.

Finally, the dragleave event will fire at an element when the drag leaves the element. This is the time when you should remove any insertion markers or highlighting. You do not need to cancel this event. Any highlighting or other visual effects specified using the -moz-drag-over pseudoclass will be removed automatically. The dragleave event will always fire, even if the drag is cancelled, so you can always ensure that any insertion point cleanup can be done during this event.

Performing a Drop

When the user releases the mouse, the drag and drop operation ends. If the mouse was released over an element that is a valid drop target, that is, one that cancelled the last dragenter or dragover event, then the drop will be successful, and a drop event will fire at the target. Otherwise, the drag operation is cancelled and no drop event is fired.

During the drop event, you should retrieve that data that was dropped from the event and insert it at the drop location. You can use the dropEffect property to determine which drag operation was desired.

As with all drag related events, the event's dataTransfer property will hold the data that is being dragged. The getData method may be used to retrieve the data again.

function onDrop(event)
{
  var data = event.dataTransfer.getData("text/plain");
  event.target.textContent = data;
  event.preventDefault();
}

The getData method takes one argument, the type of data to retrieve. It will return the string value that was set when the setData was called at the beginning of the drag operation. An empty string will be returned if data of that type does not exist. Naturally though, you would likely know that the right type of data was available, as it was previously checked during a dragover event.

In the example here, once we have retrieved the data, we insert the string as the textual content of the target. This has the effect of inserting the dragged text where it was dropped, assuming that the drop target is an area of text such as a p or div element.

In a web page, you should call the preventDefault method of the event if you have accepted the drop so that the default browser handling does not handle the droppped data as well. For example, when a link is dragged to a web page, Firefox will open the link. By cancelling the event, this behaviour will be prevented.

You can retrieve other types of data as well. If the data is a link, it should have the type text/uri-list. You could then insert a link into the content.

function doDrop(event)
{
  var links = event.dataTransfer.getData("text/uri-list").split("\n");
  for each (var link in links) {
    if (link.indexOf("#") == 0)
      continue;

    var newlink = document.createElement("a");
    newlink.href = link;
    newlink.textContent = link;
    event.target.appendChild(newlink);
  }
  event.preventDefault();
}

This example inserts a link from the dragged data. As you might be able to guess from the name, the text/uri-list type actually may contain a list of URLs, each on a separate line. In this code, we use the split to split the string into lines, then iterate over the list of lines, inserting each as a link into the document. Note also that we skip links starting with a number sign (#) as these are comments.

For simple cases, you can use the special type URL to just retrieve the first valid URL in the list. For example:

var link = event.dataTransfer.getData("URL");

This eliminates the need to check for comments or iterate through lines yourself, however it is limited to only the first URL in the list.

The URL type is a special type used only as a shorthand, and it does not appear within the list of types specified in the types property.

Sometimes you may support a number of different formats, and you want to retrieve the data that is most specific that is supported. In this example, three formats are support by a drop target.

The following example returns the data associated with the best supported format:

function doDrop(event)
{
  var types = event.dataTransfer.types;
  var supportedTypes = ["application/x-moz-file", "text/uri-list", "text/plain"];
  types = supportedTypes.filter(function (value) types.contains(value));
  if (types.length)
    var data = event.dataTransfer.getData(types[0]);
  event.preventDefault();
}

This method relies on JavaScript functionality available in Firefox 3. However the code could be adjusted to support other platforms.

Finishing a Drag

Once the drag is complete, a dragend is fired at the source of the drag (the same element that received the dragstart event). This event will fire if the drag was successful or if it was cancelled. However, you can use the dropEffect to determine what drop operation occurred.

If the dropEffect property has the value none during a dragend, then the drag was cancelled. Otherwise, the effect specifies which operation was performed. The source can use this information after a move operation to remove the dragged item from the old location. The mozUserCancelled property will be set to true if the user cancelled the drag (by pressing Escape), and false if the drag was cancelled for other reasons such as an invalid drop target, or if it was successful.

A drop can occur inside the same window or over another application. The dragend event will always fire regardless. The event's screenX and screenY properties will be set to the screen coordinate where the drop occurred.

After the dragend event has finished propagating, the drag and drop operation is complete.

{{ languages( { "ja": "Ja/DragDrop/Drag_Operations" } ) }}

Revision Source

<p>The following describes the steps that occur during a drag and drop operation.</p>
<h2 id="draggableattribute" name="draggableattribute">The Draggable Attribute</h2>
<p>Within a web page, there are certain cases where a default drag behaviour is used. These include text selections, images and links. When an image or link is dragged, the URL of the image or link is set as the drag data, and a drag begins. For other elements, they must be part of a selection in order for a default drag to occur. To see this in effect, select an area of a web page, and then click and hold the mouse and drag the selection. An OS-specific rendering of the selection will appear and follow the mouse pointer as the drag occurs. However, this behaviour is only the default drag behaviour, if no listeners adjust the data to be dragged.</p>
<p>In HTML, apart from the default behaviour for images, links and selections, no other elements are draggable by default. All XUL elements are also draggable. In order to make another HTML element draggable, two things must be done:</p>
<ul>
  <li>Set the <code>draggable</code> attribute to <code>true</code> on the element that you wish to make draggable.</li>
  <li>Add a listener for the <code>dragstart</code> event and set the drag data within this listener.</li>
</ul>
<p>Here is an example which allows a section of content to be dragged.</p>
<pre>
&lt;div draggable="true" ondragstart="event.dataTransfer.setData('text/plain', 'This text may be dragged')"&gt;
  This text &lt;strong&gt;may&lt;/strong&gt; be dragged.
&lt;/div&gt;
</pre>
<p>The <code>draggable</code> attribute is set to true, so this element becomes draggable. If this attribute was omitted or set to false, the element would not be dragged and instead the text would be selected. The <code>draggable</code> may be used on any element, including images and links. However, for these last two, the default value is true, so you would generally only use the <code>draggable</code> attribute with a value of <code>false</code> to disable dragging of these elements.</p>
<p>Note that when an element is made draggable, text or other elements within it can no longer be selected in the normal way by clicking and dragging with the mouse. Instead, the user must hold down the Alt key to select text with the mouse, or use the keyboard.</p>
<p>For XUL elements, you do not need to use the <code>draggable</code> attribute, as all XUL elements are draggable.</p>
<pre>
&lt;button label="Drag Me" ondragstart="event.dataTransfer.setData('text/plain', 'Drag Me Button');"&gt;
</pre>
<h2 id="dragstart" name="dragstart">Starting a Drag Operation</h2>
<p>In this example, a listener is added for the dragstart event by using the <code>ondragstart</code> attribute.</p>
<pre>
&lt;div draggable="true" ondragstart="event.dataTransfer.setData('text/plain', 'This text may be dragged')"&gt;
  This text &lt;strong&gt;may&lt;/strong&gt; be dragged.
&lt;/div&gt;
</pre>
<p>When a user begins to drag, the dragstart event is fired. In this example the dragstart listener is added to the draggable element itself, however, you could listen to a higher ancestor as drag events bubble up as most other events do. Within the dragstart event, you can specify the drag data, the feedback image and the drag effects, all of which are described below. However, only the drag data is required; the default image and drag effects are suitable in many situations.</p>
<h2 id="dragdata" name="dragdata">Drag Data</h2>
<p>All drag events have a property called <a href="/En/DragDrop/DataTransfer" title="dataTransfer">dataTransfer</a> which is used to hold the drag data.</p>
<p>When a drag occurs, data must be associated with the drag which identifies what is being dragged. For example, when dragging the selected text within a textbox, the data associated with the drag is the text itself. Similarly, when dragging a link on a web page, the drag data is the URL of the link.</p>
<p>The drag data contains two pieces of information, the type, or format, or the data, and the data value. The format is a type string (such as <a href="/En/DragDrop/Recommended_Drag_Types#text" title="text/plain">text/plain</a> for text data), and the value is a string of text. When the drag begins, you would add data by providing a type and the data. During the drag, in an event listener for the <code>dragenter</code> and <code>dragover</code> events, you would use the types of the data being dragged to check whether a drop is allowed. For instance, a drop target that accepts links would check for the link type <a href="/En/DragDrop/Recommended_Drag_Types#link" title="text/uri-list">text/uri-list</a>. During a drop event, a listener would retrieve the data being dragged and insert it at the drop location.</p>
<p>Types are a MIME-type like string, such as <a href="/En/DragDrop/Recommended_Drag_Types#text" title="text/plain">text/plain</a> or <a href="/En/DragDrop/Recommended_Drag_Types#image" title="image/jpeg">image/jpeg</a>. You can also create your own types. The most commonly used types are listed at <a href="/en/DragDrop/DataTypes" title="Data Types">Drag Types</a>.</p>
<p>A drag may provide data of several different types. This allows data to be provided in more specific types, often custom types, yet still provide fallback data for drop targets that do not support more specific types. It is usually always the case that the least specific type will be normal text data using the type <a href="/En/DragDrop/Recommended_Drag_Types#text" title="text/plain">text/plain</a>. This data will be a simple textual representation.</p>
<p>To set data within the dataTransfer, use the <a href="/En/DragDrop/DataTransfer#setData.28.29" title="setData">setData</a> method. It takes two arguments, the type of data, and the data value. For example:</p>
<pre>
event.dataTransfer.setData("text/plain", "Text to drag");
</pre>
<p>In this case, the data value is "Text to drag" and is of the format <a href="/En/DragDrop/Recommended_Drag_Types#text" title="text/plain">text/plain</a>.</p>
<p>You can provide data in multiple formats. To do this, call the <a href="/En/DragDrop/DataTransfer#setData.28.29" title="setData">setData</a> method multiple times with different formats. You should call it with formats in order from most specific to least specific.</p>
<pre>
var dt = event.dataTransfer;
dt.setData("application/x-bookmark", bookmarkString);
dt.setData("text/uri-list", "http://www.mozilla.org");
dt.setData("text/plain", "http://www.mozilla.org");
</pre>
<p>Here, data is added in three different types. The first type 'application/x-bookmark' is a custom type. Other applications won't support this type, but you can use a custom type for drags between areas of the same site or application. By providing data in other types as well, we can also support drags to other applications in less specific forms. The 'application/x-bookmark' type can provide data with more details for use within the application whereas the other types can include just a single URL or text version.</p>
<p>Note that both the <a href="/En/DragDrop/Recommended_Drag_Types#link" title="text/uri-list">text/uri-list</a> and <a href="/En/DragDrop/Recommended_Drag_Types#text" title="text/plain">text/plain</a> contain the same data in this example. This will often be true, but doesn't need to be the case.</p>
<p>If you attempt to add data twice with the same format, the new data will replace the old data, but in the same position within the list of types as the old data.</p>
<p>You can clear the data using the <a href="/En/DragDrop/DataTransfer#clearData.28.29" title="clearData">clearData</a> method, which takes one argument, the type of the data to remove.</p>
<pre>
event.dataTransfer.clearData("text/uri-list");
</pre>
<p>The type argument to the <a href="/En/DragDrop/DataTransfer#clearData.28.29" title="clearData">clearData</a> method is optional. If the type is not specified, the data associated with all types is removed. If no data is added to be dragged, or it is all subsequently cleared, then no drag will occur.</p>
<h2 id="dragfeedback" name="dragfeedback">Setting the drag feedback image</h2>
<p>When a drag occurs, an translucent image is generated from the drag target (the element the "dragstart" event is fired at), and follows the mouse pointer during the drag. This image is created automatically so you do not need to create it yourself. However, you can use the <code><a href="/En/DragDrop/DataTransfer#setDragImage.28.29" title="setDragImage">setDragImage()</a></code> to specify a custom drag feedback image.</p>
<pre>
event.dataTransfer.setDragImage(image, xOffset, yOffset);
</pre>
<p>Three arguments are necessary. The first is a reference to an image. This reference will typically be to an image element but it can also be to a canvas or any other element. The feedback image will simply be generated from whatever the image looks like on screen, although for images, they will be drawn at their original size. It is also possible to use images and canvases that are not in a document, as in the following example:</p>
<pre class="brush: js">
function dragWithCustomImage(event) {
  var canvas = document.createElementNS("http://www.w3.org/1999/xhtml","canvas");
  canvas.width = canvas.height = 50;

  var ctx = canvas.getContext("2d");
  ctx.lineWidth = 4;
  ctx.moveTo(0, 0);
  ctx.lineTo(50, 50);
  ctx.moveTo(0, 50);
  ctx.lineTo(50, 0);
  ctx.stroke();

  var dt = event.dataTransfer;
  dt.setData('text/plain', 'Data to Drag');
  dt.setDragImage(canvas, 25, 25);
}
</pre>
<p>This technique is useful when drawing custom drag images using the canvas element.</p>
<p>The second and third arguments to the <code><a href="/En/DragDrop/DataTransfer#setDragImage.28.29" title="setDragImage">setDragImage()</a></code> method are offsets where the image should appear relative to the mouse pointer. In this example, as the canvas is 50 pixels wide and 50 pixels high, we use offsets half of this (25 and 25) so that the image appears centered on the mouse pointer.</p>
<p>{{ h2_gecko_minversion("Using XUL panels as drag images", "9.0") }}</p>
<p>For Gecko developers (whether you're doing an add-on or Mozilla application code), Gecko 9.0 {{ geckoRelease("9.0") }} adds support for using a XUL {{ XULElem("panel") }} element as a drag feedback image. Simply pass your {{ XULElem("panel") }} element to the <code><a href="/En/DragDrop/DataTransfer#setDragImage.28.29" title="setDragImage">setDragImage()</a></code> method.</p>
<p>Consider this XUL {{ XULElem("panel") }}:</p>
<pre class="brush: xml">
&lt;<span class="start-tag">panel</span><span class="attribute-name"> id</span>=<span class="attribute-value">"panel" </span><span class="attribute-name">style</span>=<span class="attribute-value">"opacity: 0.6</span><span class="attribute-value">"</span>&gt;
  &lt;<span class="start-tag">description</span><span class="attribute-name"> id</span>=<span class="attribute-value">"pb"</span>&gt;Drag Me&lt;/<span class="end-tag">description</span>&gt;
&lt;/<span class="end-tag">panel</span>&gt;

&lt;<span class="start-tag">vbox</span><span class="attribute-name"> align</span>=<span class="attribute-value">"start" </span><span class="attribute-name">style</span>=<span class="attribute-value">"border: 1px solid black;" </span><span class="attribute-name">ondragstart</span>=<span class="attribute-value">"startDrag(event)"</span>&gt;
  &lt;<span class="start-tag">description</span>&gt;Drag Me&lt;/<span class="end-tag">description</span>&gt;
&lt;/<span class="end-tag">vbox</span>&gt;
</pre>
<p>When the user begins a drag by clicking and dragging from the {{ XULElem("vbox") }} above, the <code>startDrag()</code> function below is called.</p>
<pre class="brush: js">
<span class="cdata">function startDrag(event) {
  event.dataTransfer.setData("text/plain", "&lt;strong&gt;Body&lt;/strong&gt;");
  event.dataTransfer.setDragImage(document.getElementById("panel"), 20, 20);
}</span>
</pre>
<p>This uses the panel as the drag image, with the string "&lt;strong&gt;Body&lt;/strong&gt;" as its data, in HTML format. Dropping the panel into a text editor results in the text "<strong>Body</strong>" being inserted into the text at the drop location.</p>
<h2 id="drageffects" name="drageffects">Drag Effects</h2>
<p>When dragging, there are several operations that may be performed. The <code>copy</code> operation is used to indicate that the data being dragged will be copied from its present location to the drop location. The <code>move</code> operation is used to indicate that the data being dragged will be moved, and the <code>link</code> operation is used to indicate that some form of relationship or connection will be created between the source and drop locations.</p>
<p>You can specify which of the three operations are allowed for a drag source, by setting the <a href="/En/DragDrop/DataTransfer#effectAllowed.28.29" title="effectAllowed">effectAllowed</a> property within a <code>dragstart</code> event listener.</p>
<pre>
event.dataTransfer.effectAllowed = "copy";
</pre>
<p>In this example, only a copy is allowed. You can combine the values is various ways:</p>
<dl>
  <dt>
    none</dt>
  <dd>
    no operation is permitted</dd>
  <dt>
    copy</dt>
  <dd>
    copy only</dd>
  <dt>
    move</dt>
  <dd>
    move only</dd>
  <dt>
    link</dt>
  <dd>
    link only</dd>
  <dt>
    copyMove</dt>
  <dd>
    copy or move only</dd>
  <dt>
    copyLink</dt>
  <dd>
    copy or link only</dd>
  <dt>
    linkMove</dt>
  <dd>
    link or move only</dd>
  <dt>
    all</dt>
  <dd>
    copy, move, or link</dd>
</dl>
<p>Note that these values must be used exactly as listed above. If you don't change the <a href="/En/DragDrop/DataTransfer#effectAllowed.28.29" title="effectAllowed">effectAllowed</a> property, then any operation is allowed, just like with the 'all' value. So you don't need to adjust this property unless you want to exclude specific types.</p>
<p>During a drag operation, a listener for the <code>dragenter</code> or <code>dragover</code> events can check the <a href="/En/DragDrop/DataTransfer#effectAllowed.28.29" title="effectAllowed">effectAllowed</a> property to see which operations are permitted. A related property, <a href="/En/DragDrop/DataTransfer#dropEffect.28.29" title="dropEffect">dropEffect</a>, should be set within one of these events to specify which single operation should be performed. Valid values for the <a href="/En/DragDrop/DataTransfer#dropEffect.28.29" title="dropEffect">dropEffect</a> are <code>none</code>, <code>copy</code>, <code>move</code> or <code>link</code>. The combination values are not used for this property.</p>
<p>With the <code>dragenter</code> and <code>dragover</code> event, the <a href="/En/DragDrop/DataTransfer#dropEffect.28.29" title="dropEffect">dropEffect</a> property is initialized to the effect that the user is requesting. The user can modify the desired effect by pressing modifier keys. Although the exact keys used vary by platform, typically the Shift and Control keys would be used to switch between copying, moving and linking. The mouse pointer will change to indicate which operation is desired, for instance, for a copy, the cursor might appear with a plus sign next to it.</p>
<p>You can modify both the <a href="/En/DragDrop/DataTransfer#effectAllowed.28.29" title="effectAllowed">effectAllowed</a> and the <a href="/En/DragDrop/DataTransfer#dropEffect.28.29" title="dropEffect">dropEffect</a> property during the <code>dragenter</code> or <code>dragover</code> events, if for example, a particular drop target only supports certain operations. Modifying the <a href="/En/DragDrop/DataTransfer#effectAllowed.28.29" title="effectAllowed">effectAllowed</a> property lets you specify which set of operations are permitted at a certain drop target. For example, setting the <a href="/En/DragDrop/DataTransfer#effectAllowed.28.29" title="effectAllowed">effectAllowed</a> property to <code>copyMove</code> allows a copy or move operation but prevents the user from performing a link operation.</p>
<p>You can modify the <a href="/En/DragDrop/DataTransfer#dropEffect.28.29" title="dropEffect">dropEffect</a> property to override the user effect, and enforce a specific drop operation to occur. Note that this effect must be one listed within the <a href="/En/DragDrop/DataTransfer#effectAllowed.28.29" title="effectAllowed">effectAllowed</a> property. Otherwise, it will be set to an alternate value that is allowed.</p>
<pre>
event.dataTransfer.effectAllowed = "copyMove";
event.dataTransfer.dropEffect = "copy";
</pre>
<p>In this example, copy is the effect that is performed as the specified effect is included in the list of allowed effects.</p>
<p>You can use the value <code>none</code> for either property to indiciate that no drop is allowed at this location.</p>
<h2 id="droptargets" name="droptargets">Specifying Drop Targets</h2>
<p>A listener for the <code>dragenter</code> and <code>dragover</code> events are used to indicate valid drop targets, that is, places where dragged items may be dropped. Most areas of a web page or application are not valid places to drop data. Thus, the default handling for these events is to not allow a drop.</p>
<p>If you want to allow a drop, you must prevent the default handling by cancelling the event. You can do this either by returning <code>false</code> from an attribute-defined event listener, or by calling the event's <a href="/en/DOM/event.preventDefault" title="en/DOM/event.preventDefault">event.preventDefault</a> method. The latter may be more feasible in a function defined in a separate script.</p>
<pre>
&lt;div ondragover="return false"&gt;
&lt;div ondragover="event.preventDefault()"&gt;
</pre>
<p>Calling the <a href="/en/DOM/event.preventDefault" title="en/DOM/event.preventDefault">preventDefault</a> method during both a <code>dragenter</code> and <code>dragover</code> event will indicate that a drop is allowed at that location. However, you will commonly wish to call the <a href="/en/DOM/event.preventDefault" title="en/DOM/event.preventDefault">preventDefault</a> method only in certain situations, for example, only if a link is being dragged. To do this, call a function which checks a condition and only cancels the event when the condition is met. If the condition is not met, don't cancel the event, and a drop will not occur there if the user releases the mouse button.</p>
<p>It is most common to accept or reject a drop based on the type of drag data in the data transfer. For instance, allowing images or links or both. To do this, you can check the <a href="/En/DragDrop/DataTransfer#types.28.29" title="types">types</a> of the <code>dataTransfer</code> object. The types are a list of the string types that were added when the drag began, in the order from most significant to least significant.</p>
<pre>
function doDragOver(event)
{
  var isLink = event.dataTransfer.types.contains("text/uri-list");
  if (isLink)
    event.preventDefault();
}
</pre>
<p>In this example, we use the <code>contains</code> method to check if the type <a href="/En/DragDrop/Recommended_Drag_Types#link" title="text/uri-list">text/uri-list</a> is present in the list of types. If it is, we will cancel the event so that a drop may be allowed. If the drag data does not contain a link, the event will not be cancelled and a drop cannot occur at that location.</p>
<p>You may also wish to set either the <a href="/En/DragDrop/DataTransfer#effectAllowed.28.29" title="effectAllowed">effectAllowed</a>, <a href="/En/DragDrop/DataTransfer#dropEffect.28.29" title="dropEffect">dropEffect</a> property, or both at the same time, if you wish to be more specific about the type of operation that will performed. Naturally, changing either property will have no effect if you do not cancel the event as well.</p>
<h2 id="dropfeedback" name="dropfeedback">Drop Feedback</h2>
<p>There are several ways in which you can indicate to the user that a drop is allowed at a certain location. The mouse pointer will update as necessary depending on the value of the <a href="/En/DragDrop/DataTransfer#dropEffect.28.29" title="dropEffect">dropEffect</a> property. Although the exact appearance depends on the user's platform, typically a plus sign icon will appear for a 'copy' for example, and a 'cannot drop here' icon will appear when a drop is not allowed. This mouse pointer feedback is sufficient in many cases.</p>
<p>However, you can also update the user interface with an insertion point or highlight as needed. For simple highlighting, you can use the <code>-moz-drag-over</code> CSS pseudoclass on a drop target.</p>
<pre>
.droparea:-moz-drag-over {
  border: 1px solid black;
}
</pre>
<p>In this example, the element with the class <code>droparea</code> will receieve a 1 pixel black border while it is a valid drop target, that is, if the <a href="/en/DOM/event.preventDefault" title="en/DOM/event.preventDefault">event.preventDefault</a> method was called during the <code>dragenter</code> event. Note that you must cancel the <code>dragenter</code> event for this pseudoclass to apply, as this state is not checked for the <code>dragover</code> event.</p>
<p>For more complex visual effects, you can also perform other operations during the <code>dragenter</code> event, for example, by inserting an element at the location where the drop will occur. For example, this might be an insertion marker or an element that represents the dragged element in its new location. To do this, you could create an <a href="/en/XUL/image" title="image">image</a> or <a href="/en/XUL/separator" title="separator">separator</a> element for example, and simply insert it into the document during the <code>dragenter</code> event.</p>
<p>The <code>dragover</code> event will fire at the element the mouse is pointing at. Naturally, you may need to move the insertion marker around a <code>dragover</code> event as well. You can use the event's <a href="/en/DOM/event.clientX" title="clientX">clientX</a> and <a href="/en/DOM/event.clientY" title="clientY">clientY</a> properties as with other mouse events to determine the location of the mouse pointer.</p>
<p>Finally, the <code>dragleave</code> event will fire at an element when the drag leaves the element. This is the time when you should remove any insertion markers or highlighting. You do not need to cancel this event. Any highlighting or other visual effects specified using the <code>-moz-drag-over</code> pseudoclass will be removed automatically. The <code>dragleave</code> event will always fire, even if the drag is cancelled, so you can always ensure that any insertion point cleanup can be done during this event.</p>
<h2 id="drop" name="drop">Performing a Drop</h2>
<p>When the user releases the mouse, the drag and drop operation ends. If the mouse was released over an element that is a valid drop target, that is, one that cancelled the last <code>dragenter</code> or <code>dragover</code> event, then the drop will be successful, and a <code>drop</code> event will fire at the target. Otherwise, the drag operation is cancelled and no <code>drop</code> event is fired.</p>
<p>During the <code>drop</code> event, you should retrieve that data that was dropped from the event and insert it at the drop location. You can use the <a href="/En/DragDrop/DataTransfer#dropEffect.28.29" title="dropEffect">dropEffect</a> property to determine which drag operation was desired.</p>
<p>As with all drag related events, the event's <code>dataTransfer</code> property will hold the data that is being dragged. The <a href="/En/DragDrop/DataTransfer#getData.28.29" title="getData">getData</a> method may be used to retrieve the data again.</p>
<pre>
function onDrop(event)
{
  var data = event.dataTransfer.getData("text/plain");
  event.target.textContent = data;
  event.preventDefault();
}
</pre>
<p>The <a href="/En/DragDrop/DataTransfer#getData.28.29" title="getData">getData</a> method takes one argument, the type of data to retrieve. It will return the string value that was set when the <a href="/En/DragDrop/DataTransfer#setData.28.29" title="setData">setData</a> was called at the beginning of the drag operation. An empty string will be returned if data of that type does not exist. Naturally though, you would likely know that the right type of data was available, as it was previously checked during a <code>dragover</code> event.</p>
<p>In the example here, once we have retrieved the data, we insert the string as the textual content of the target. This has the effect of inserting the dragged text where it was dropped, assuming that the drop target is an area of text such as a <code>p</code> or <code>div</code> element.</p>
<p>In a web page, you should call the <a href="/en/DOM/event.preventDefault" title="en/DOM/event.preventDefault">preventDefault</a> method of the event if you have accepted the drop so that the default browser handling does not handle the droppped data as well. For example, when a link is dragged to a web page, Firefox will open the link. By cancelling the event, this behaviour will be prevented.</p>
<p>You can retrieve other types of data as well. If the data is a link, it should have the type <a href="/En/DragDrop/Recommended_Drag_Types#link" title="text/uri-list">text/uri-list</a>. You could then insert a link into the content.</p>
<pre>
function doDrop(event)
{
  var links = event.dataTransfer.getData("text/uri-list").split("\n");
  for each (var link in links) {
    if (link.indexOf("#") == 0)
      continue;

    var newlink = document.createElement("a");
    newlink.href = link;
    newlink.textContent = link;
    event.target.appendChild(newlink);
  }
  event.preventDefault();
}
</pre>
<p>This example inserts a link from the dragged data. As you might be able to guess from the name, the <a href="/En/DragDrop/Recommended_Drag_Types#link" title="text/uri-list">text/uri-list</a> type actually may contain a list of URLs, each on a separate line. In this code, we use the <a href="/en/Core_JavaScript_1.5_Reference/Global_Objects/String/split" title="split">split</a> to split the string into lines, then iterate over the list of lines, inserting each as a link into the document. Note also that we skip links starting with a number sign (#) as these are comments.</p>
<p>For simple cases, you can use the special type <code>URL</code> to just retrieve the first valid URL in the list. For example:</p>
<pre>
var link = event.dataTransfer.getData("URL");
</pre>
<p>This eliminates the need to check for comments or iterate through lines yourself, however it is limited to only the first URL in the list.</p>
<p>The <code>URL</code> type is a special type used only as a shorthand, and it does not appear within the list of types specified in the <a href="/En/DragDrop/DataTransfer#types.28.29" title="types">types</a> property.</p>
<p>Sometimes you may support a number of different formats, and you want to retrieve the data that is most specific that is supported. In this example, three formats are support by a drop target.</p>
<p>The following example returns the data associated with the best supported format:</p>
<pre>
function doDrop(event)
{
  var types = event.dataTransfer.types;
  var supportedTypes = ["application/x-moz-file", "text/uri-list", "text/plain"];
  types = supportedTypes.filter(function (value) types.contains(value));
  if (types.length)
    var data = event.dataTransfer.getData(types[0]);
  event.preventDefault();
}
</pre>
<p>This method relies on JavaScript functionality available in Firefox 3. However the code could be adjusted to support other platforms.</p>
<h2 id="dragend" name="dragend">Finishing a Drag</h2>
<p>Once the drag is complete, a <code>dragend</code> is fired at the source of the drag (the same element that received the <code>dragstart</code> event). This event will fire if the drag was successful or if it was cancelled. However, you can use the <a href="/En/DragDrop/DataTransfer#dropEffect.28.29" title="dropEffect">dropEffect</a> to determine what drop operation occurred.</p>
<p>If the <a href="/En/DragDrop/DataTransfer#dropEffect.28.29" title="dropEffect">dropEffect</a> property has the value <code>none</code> during a <code>dragend</code>, then the drag was cancelled. Otherwise, the effect specifies which operation was performed. The source can use this information after a move operation to remove the dragged item from the old location. The <a href="/En/DragDrop/DataTransfer#mozUserCancelled.28.29" title="dropEffect">mozUserCancelled</a> property will be set to true if the user cancelled the drag (by pressing Escape), and false if the drag was cancelled for other reasons such as an invalid drop target, or if it was successful.</p>
<p>A drop can occur inside the same window or over another application. The <code>dragend</code> event will always fire regardless. The event's <a href="/en/DOM/event.screenX" title="screenX">screenX</a> and <a href="/en/DOM/event.screenY" title="screenY">screenY</a> properties will be set to the screen coordinate where the drop occurred.</p>
<p>After the <code>dragend</code> event has finished propagating, the drag and drop operation is complete.</p>
<p>{{ languages( { "ja": "Ja/DragDrop/Drag_Operations" } ) }}</p>
Revert to this revision