This is a snapshot of an early working draft and has therefore been superseded by the HTML standard.

This document will not be further updated.

HTML 5

Call For Comments — 27 October 2007

5.3. Drag and drop

This section defines an event-based drag-and-drop mechanism.

This specification does not define exactly what a drag-and-drop operation actually is.

On a visual medium with a pointing device, a drag operation could be the default action of a mousedown event that is followed by a series of mousemove events, and the drop could be triggered by the mouse being released.

On media without a pointing device, the user would probably have to explicitly indicate his intention to perform a drag-and-drop operation, stating what he wishes to drag and what he wishes to drop, respectively.

However it is implemented, drag-and-drop operations must have a starting point (e.g. where the mouse was clicked, or the start of the selection or element that was selected for the drag), may have any number of intermediate steps (elements that the mouse moves over during a drag, or elements that the user picks as possible drop points as he cycles through possibilities), and must either have an end point (the element above which the mouse button was released, or the element that was finally selected), or be canceled. The end point must be the last element selected as a possible drop point before the drop occurs (so if the operation is not canceled, there must be at least one element in the middle step).

5.3.1. The DragEvent and DataTransfer interfaces

The drag-and-drop processing model involves several events. They all use the DragEvent interface.

interface DragEvent : UIEvent {
  readonly attribute DataTransfer dataTransfer;
  void initDragEvent(in DOMString typeArg, in boolean canBubbleArg, in boolean cancelableArg, in AbstractView viewArg, in long detailArg, in DataTransfer dataTransferArg);
  void initDragEventNS(in DOMString namespaceURIArg, in DOMString typeArg, in boolean canBubbleArg, in boolean cancelableArg, in AbstractView viewArg, in long detailArg, in DataTransfer dataTransferArg);
};

We should have modifier key information in here too (shift/ctrl, etc), like with mouse events and like with the context menu event.

The initDragEvent() and initDragEventNS() methods must initialise the event in a manner analogous to the similarly-named methods in the DOM3 Events interfaces. [DOM3EVENTS]

The dataTransfer attribute of the DragEvent interface represents the context information for the event.

When a DragEvent object is created, a new DataTransfer object must be created and assigned to the dataTransfer context information field of the event object.

interface DataTransfer {
           attribute DOMString dropEffect;
           attribute DOMString effectAllowed;
  void clearData(in DOMString format);
  void setData(in DOMString format, in DOMString data);
  DOMString getData(in DOMString format);
  void setDragImage(in Element image, in long x, in long y);
  void addElement(in Element element);
};

DataTransfer objects can conceptually contain various kinds of data.

When a DragEvent event object is initialised, the DataTransfer object created for the event's dataTransfer member must be initialised as follows:

The dropEffect attribute controls the drag-and-drop feedback that the user is given during a drag-and-drop operation.

The attribute must ignore any attempts to set it to a value other than none, copy, link, and move. On getting, the attribute must return the last of those four values that it was set to.

The effectAllowed attribute is used in the drag-and-drop processing model to initialise the dropEffect attribute during the dragenter and dragover events.

The attribute must ignore any attempts to set it to a value other than none, copy, copyLink, copyMove, link, linkMove, move, all, and uninitialized. On getting, the attribute must return the last of those values that it was set to.

DataTransfer objects can hold pieces of data, each associated with a unique format. Formats are generally given by MIME types, with some values special-cased for legacy reasons.

The clearData(format) method must clear the DataTransfer object of any data associated with the given format. If format is the value "Text", then it must be treated as "text/plain". If the format is "URL", then it must be treated as "text/uri-list".

The setData(format, data) method must add data to the data stored in the DataTransfer object, labelled as being of the type format. This must replace any previous data that had been set for that format. If format is the value "Text", then it must be treated as "text/plain". If the format is "URL", then it must be treated as "text/uri-list".

The getData(format) method must return the data that is associated with the type format, if any, and must return the empty string otherwise. If format is the value "Text", then it must be treated as "text/plain". If the format is "URL", then the data associated with the "text/uri-list" format must be parsed as appropriate for text/uri-list data, and the first URI from the list must be returned. If there is no data with that format, or if there is but it has no URIs, then the method must return the empty string. [RFC2483]

The setDragImage(element, x, y) method sets which element to use to generate the drag feedback. The element argument can be any Element; if it is an img element, then the user agent should use the element's image (at its intrinsic size) to generate the feedback, otherwise the user agent should base the feedback on the given element (but the exact mechanism for doing so is not specified).

The addElement(element) method is an alternative way of specifying how the user agent is to render the drag feedback. It adds an element to the DataTransfer object.

5.3.2. Events fired during a drag-and-drop action

The following events are involved in the drag-and-drop model. Whenever the processing model described below causes one of these events to be fired, the event fired must use the DragEvent interface defined above, must have the bubbling and cancelable behaviours given in the table below, and must have the context information set up as described after the table, with the view attribute set to the view with which the user interacted to trigger the drag-and-drop event, and the detail attribute set to zero.

Event Name Target Bubbles? Cancelable? dataTransfer effectAllowed dropEffect Default Action
dragstart Source node ✓ Bubbles ✓ Cancelable Contains source node unless a selection is being dragged, in which case it is empty uninitialized none Initiate the drag-and-drop operation
drag Source node ✓ Bubbles ✓ Cancelable Empty Same as last event none Continue the drag-and-drop operation
dragenter Immediate user selection or the body element ✓ Bubbles ✓ Cancelable Empty Same as last event Based on effectAllowed value Reject immediate user selection as potential target element
dragleave Previous target element ✓ Bubbles Empty Same as last event none None
dragover Current target element ✓ Bubbles ✓ Cancelable Empty Same as last event Based on effectAllowed value Reset the current drag operation to "none"
drop Current target element ✓ Bubbles ✓ Cancelable getData() returns data set in dragstart event Same as last event Current drag operation Varies
dragend Source node ✓ Bubbles Empty Same as last event Current drag operation Varies

The dataTransfer object's contents are empty except for dragstart events and drop events, for which the contents are set as described in the processing model, below.

The effectAllowed attribute must be set to "uninitialized" for dragstart events, and to whatever value the field had after the last drag-and-drop event was fired for all other events (only counting events fired by the user agent for the purposes of the drag-and-drop model described below).

The dropEffect attribute must be set to "none" for dragstart, drag, and dragleave events (except when stated otherwise in the algorithms given in the sections below), to the value corresponding to the current drag operation for drop and dragend events, and to a value based on the effectAllowed attribute's value and to the drag-and-drop source, as given by the following table, for the remaining events (dragenter and dragover):

effectAllowed dropEffect
none none
copy, copyLink, copyMove, all copy
link, linkMove link
move move
uninitialized when what is being dragged is a selection from a text field move
uninitialized when what is being dragged is a selection copy
uninitialized when what is being dragged is an a element with an href attribute link
Any other case copy

5.3.3. Drag-and-drop processing model

When the user attempts to begin a drag operation, the user agent must first determine what is being dragged. If the drag operation was invoked on a selection, then it is the selection that is being dragged. Otherwise, it is the first element, going up the ancestor chain, starting at the node that the user tried to drag, that has the DOM attribute draggable set to true. If there is no such element, then nothing is being dragged, the drag-and-drop operation is never started, and the user agent must not continue with this algorithm.

img elements and a elements with an href attribute have their draggable attribute set to true by default.

If the user agent determines that something can be dragged, a dragstart event must then be fired.

If it is a selection that is being dragged, then this event must be fired on the node that the user started the drag on (typically the text node that the user originally clicked). If the user did not specify a particular node, for example if the user just told the user agent to begin a drag of "the selection", then the event must be fired on the deepest node that is a common ancestor of all parts of the selection.

We should look into how browsers do other types (e.g. Firefox apparently also adds text/html for internal drag and drop of a selection).

If it is not a selection that is being dragged, then the event must be fired on the element that is being dragged.

The node on which the event is fired is the source node. Multiple events are fired on this node during the course of the drag-and-drop operation.

If it is a selection that is being dragged, the dataTransfer member of the event must be created with no nodes. Otherwise, it must be created containing just the source node. Script can use the addElement() method to add further elements to the list of what is being dragged.

If it is a selection that is being dragged, the dataTransfer member of the event must have the text of the selection added to it as the data associated with the text/plain format. Otherwise, if it is an img element being dragged, then the value of the element's src DOM attribute must be added, associated with the text/uri-list format. Otherwise, if it is an a element being dragged, then the value of the element's href DOM attribute must be added, associated with the text/uri-list format. Otherwise, no data is added to the object by the user agent.

If the event is canceled, then the drag-and-drop operation must not occur; the user agent must not continue with this algorithm.

If it is not canceled, then the drag-and-drop operation must be initiated.

Since events with no event handlers registered are, almost by definition, never canceled, drag-and-drop is always available to the user if the author does not specifically prevent it.

The drag-and-drop feedback must be generated from the first of the following sources that is available:

  1. The element specified in the last call to the setDragImage() method of the dataTransfer object of the dragstart event, if the method was called. In visual media, if this is used, the x and y arguments that were passed to that method should be used as hints for where to put the cursor relative to the resulting image. The values are expressed as distances in CSS pixels from the left side and from the top side of the image respectively. [CSS21]
  2. The elements that were added to the dataTransfer object, both before the event was fired, and during the handling of the event using the addElement() method, if any such elements were indeed added.
  3. The selection that the user is dragging.

The user agent must take a note of the data that was placed in the dataTransfer object. This data will be made available again when the drop event is fired.

From this point until the end of the drag-and-drop operation, device input events (e.g. mouse and keyboard events) must be suppressed. In addition, the user agent must track all DOM changes made during the drag-and-drop operation, and add them to its undo history as one atomic operation once the drag-and-drop operation has ended.

During the drag operation, the element directly indicated by the user as the drop target is called the immediate user selection. (Only elements can be selected by the user; other nodes must not be made available as drop targets.) However, the immediate user selection is not necessarily the current target element, which is the element currently selected for the drop part of the drag-and-drop operation. The immediate user selection changes as the user selects different elements (either by pointing at them with a pointing device, or by selecting them in some other way). The current target element changes when the immediate user selection changes, based on the results of event handlers in the document, as described below.

Both the current target element and the immediate user selection can be null, which means no target element is selected. They can also both be elements in other (DOM-based) documents, or other (non-Web) programs altogether. (For example, a user could drag text to a word-processor.) The current target element is initially null.

In addition, there is also a current drag operation, which can take on the values "none", "copy", "link", and "move". Initially it has the value "none". It is updated by the user agent as described in the steps below.

User agents must, every 350ms (±200ms), perform the following steps in sequence. (If the user agent is still performing the previous iteration of the sequence when the next iteration becomes due, the user agent must not execute the overdue iteration, effectively "skipping missed frames" of the drag-and-drop operation.)

  1. First, the user agent must fire a drag event at the source node. If this event is canceled, the user agent must set the current drag operation to none (no drag operation).

  2. Next, if the drag event was not canceled and the user has not ended the drag-and-drop operation, the user agent must check the state of the drag-and-drop operation, as follows:

    1. First, if the user is indicating a different immediate user selection than during the last iteration (or if this is the first iteration), and if this immediate user selection is not the same as the current target element, then the current target element must be updated, as follows:

      1. If the new immediate user selection is null, or is in a non-DOM document or application, then set the current target element to the same value.

      2. Otherwise, the user agent must fire a dragenter event at the immediate user selection.

      3. If the event is canceled, then the current target element must be set to the immediate user selection.

      4. Otherwise, if the current target element is not the body element, the user agent must fire a dragenter event at the body element, and the current target element must be set to the body element, regardless of whether that event was canceled or not. (If the body element is null, then the current target element would be set to null too in this case, it wouldn't be set to the Document object.)

    2. If the previous step caused the current target element to change, and if the previous target element was not null or a part of a non-DOM document, the user agent must fire a dragleave event at the previous target element.

    3. If the current target element is a DOM element, the user agent must fire a dragover event at this current target element.

      If the dragover event is canceled, the current drag operation must be reset to "none".

      Otherwise, the current drag operation must be set based on the values the effectAllowed and dropEffect attributes of the dataTransfer object had after the event was handled, as per the following table:

      effectAllowed dropEffect Drag operation
      uninitialized, copy, copyLink, copyMove, or all copy "copy"
      uninitialized, link, copyLink, linkMove, or all link "link"
      uninitialized, move, copyMove, linkMove, or all move "move"
      Any other case "none"

      Then, regardless of whether the dragover event was canceled or not, the drag feedback (e.g. the mouse cursor) must be updated to match the current drag operation, as follows:

      Drag operation Feedback
      "copy" Data will be copied if dropped here.
      "link" Data will be linked if dropped here.
      "move" Data will be moved if dropped here.
      "none" No operation allowed, dropping here will cancel the drag-and-drop operation.
    4. Otherwise, if the current target element is not a DOM element, the user agent must use platform-specific mechanisms to determine what drag operation is being performed (none, copy, link, or move). This sets the current drag operation.

  3. Otherwise, if the user ended the drag-and-drop operation (e.g. by releasing the mouse button in a mouse-driven drag-and-drop interface), or if the drag event was canceled, then this will be the last iteration. The user agent must execute the following steps, then stop looping.

    1. If the current drag operation is none (no drag operation), or, if the user ended the drag-and-drop operation by canceling it (e.g. by hitting the Escape key), or if the current target element is null, then the drag operation failed. If the current target element is a DOM element, the user agent must fire a dragleave event at it; otherwise, if it is not null, it must use platform-specific conventions for drag cancellation.

    2. Otherwise, the drag operation was as success. If the current target element is a DOM element, the user agent must fire a drop event at it; otherwise, it must use platform-specific conventions for indicating a drop.

      When the target is a DOM element, the dropEffect attribute of the event's dataTransfer object must be given the value representing the current drag operation (copy, link, or move), and the object must be set up so that the getData() method will return the data that was added during the dragstart event.

      If the event is canceled, the current drag operation must be set to the value of the dropEffect attribute of the event's dataTransfer object as it stood after the event was handled.

      Otherwise, the event is not canceled, and the user agent must perform the event's default action, which depends on the exact target as follows:

      If the current target element is a text field (e.g. textarea, or an input element with type="text")
      The user agent must insert the data associated with the text/plain format, if any, into the text field in a manner consistent with platform-specific conventions (e.g. inserting it at the current mouse cursor position, or inserting it at the end of the field).
      Otherwise
      Reset the current drag operation to "none".
    3. Finally, the user agent must fire a dragend event at the source node, with the dropEffect attribute of the event's dataTransfer object being set to the value corresponding to the current drag operation.

      The current drag operation can change during the processing of the drop event, if one was fired.

      The event is not cancelable. After the event has been handled, the user agent must act as follows:

      If the current target element is a text field (e.g. textarea, or an input element with type="text"), and a drop event was fired in the previous step, and the current drag operation is "move", and the source of the drag-and-drop operation is a selection in the DOM
      The user agent should delete the range representing the dragged selection from the DOM.
      If the current target element is a text field (e.g. textarea, or an input element with type="text"), and a drop event was fired in the previous step, and the current drag operation is "move", and the source of the drag-and-drop operation is a selection in a text field
      The user agent should delete the dragged selection from the relevant text field.
      Otherwise
      The event has no default action.
5.3.3.1. When the drag-and-drop operation starts or ends in another document

The model described above is independent of which Document object the nodes involved are from; the events must be fired as described above and the rest of the processing model must be followed as described above, irrespective of how many documents are involved in the operation.

5.3.3.2. When the drag-and-drop operation starts or ends in another application

If the drag is initiated in another application, the source node is not a DOM node, and the user agent must use platform-specific conventions instead when the requirements above involve the source node. User agents in this situation must act as if the dragged data had been added to the DataTransfer object when the drag started, even though no dragstart event was actually fired; user agents must similarly use platform-specific conventions when deciding on what drag feedback to use.

If a drag is started in a document but ends in another application, then the user agent must instead replace the parts of the processing model relating to handling the target according to platform-specific conventions.

In any case, scripts running in the context of the document must not be able to distinguish the case of a drag-and-drop operation being started or ended in another application from the case of a drag-and-drop operation being started or ended in another document from another domain.

5.3.4. The draggable attribute

All elements may have the draggable content attribute set. The draggable attribute is an enumerated attribute. It has three states. The first state is true and it has the keyword true. The second state is false and it has the keyword false. The third state is auto; it has no keywords but it is the missing value default.

The draggable DOM attribute, whose value depends on the content attribute's in the way described below, controls whether or not the element is draggable. Generally, only text selections are draggable, but elements whose draggable DOM attribute is true become draggable as well.

If an element's draggable content attribute has the state true, the draggable DOM attribute must return true.

Otherwise, if the element's draggable content attribute has the state false, the draggable DOM attribute must return false.

Otherwise, the element's draggable content attribute has the state auto. If the element is an img element, or, if the element is an a element with an href content attribute, the draggable DOM attribute must return true.

Otherwise, the draggable DOM must return false.

If the draggable DOM attribute is set to the value false, the draggable content attribute must be set to the literal value false. If the draggable DOM attribute is set to the value true, the draggable content attribute must be set to the literal value true.

5.3.5. Copy and paste

Copy-and-paste is a form of drag-and-drop: the "copy" part is equivalent to dragging content to another application (the "clipboard"), and the "paste" part is equivalent to dragging content from another application.

Select-and-paste (a model used by mouse operations in the X Window System) is equivalent to a drag-and-drop operation where the source is the selection.

5.3.5.1. Copy to clipboard

When the user invokes a copy operation, the user agent must act as if the user had invoked a drag on the current selection. If the drag-and-drop operation initiates, then the user agent must act as if the user had indicated (as the immediate user selection) a hypothetical application representing the clipbroad. Then, the user agent must act as if the user had ended the drag-and-drop operation without canceling it. If the drag-and-drop operation didn't get canceled, the user agent should then follow the relevant platform-specific conventions for copy operations (e.g. updating the clipboard).

5.3.5.2. Cut to clipboard

When the user invokes a cut operation, the user agent must act as if the user had invoked a copy operation (see the previous section), followed, if the copy was completed successfully, by a selection delete operation.

5.3.5.3. Paste from clipboard

When the user invokes a clipboard paste operation, the user agent must act as if the user had invoked a drag on a hypothetical application representing the clipboard, setting the data associated with the drag as the text from the keyboard (either as text/plain or text/uri-list). If the contents of the clipboard cannot be represented as text or URIs, then the paste operation must not have any effect.

Then, the user agent must act as if the user had indicated (as the immediate user selection) the element with the keyboard focus, and then ended the drag-and-drop operation without canceling it.

5.3.5.4. Paste from selection

When the user invokes a selection paste operation, the user agent must act as if the user had invoked a drag on the current selection, then indicated (as the immediate user selection) the element with the keyboard focus, and then ended the drag-and-drop operation without canceling it.

If the contents of the selection cannot be represented as text or URIs, then the paste operation must not have any effect.

5.3.6. Security risks in the drag-and-drop model

User agents must not make the data added to the DataTransfer object during the dragstart event available to scripts until the drop event, because otherwise, if a user were to drag sensitive information from one document to a second document, crossing a hostile third document in the process, the hostile document could intercept the data.

For the same reason, user agents must only consider a drop to be successful if the user specifically ended the drag operation — if any scripts end the drag operation, it must be considered unsuccessful (canceled) and the drop event must not be fired.

User agents should take care to not start drag-and-drop operations in response to script actions. For example, in a mouse-and-window environment, if a script moves a window while the user has his mouse button depressed, the UA would not consider that to start a drag. This is important because otherwise UAs could cause data to be dragged from sensitive sources and dropped into hostile documents without the user's consent.