How DataTransfer Passes Files and Text in JavaScript

The HTML5 Drag and Drop API relies on the DataTransfer object to hold and transfer data between a drag source and a drop zone. This object acts as a shared clipboard during the drag operation, holding data types, format specifications, and file lists. By listening to specific drag events, JavaScript developers can populate the DataTransfer object with plain text, HTML, custom data, or binary files, and subsequently extract those payloads when the user releases the mouse over a designated drop target.

The Role of the DataTransfer Object

When a drag operation begins, the browser creates a DataTransfer instance accessible via the dataTransfer property of the DragEvent. This object serves as the bridge between the element being dragged (the source) and the element receiving the drop (the target). It persists throughout the drag-and-drop lifecycle, exposing methods to set and retrieve data, configure visual drag feedback, and determine allowed drop effects such as copying or moving.

Setting Up Drop Zones

For an element to accept dragged data or files, it must be designated as a drop zone. Browsers prevent drops on most elements by default, so the default behavior must be canceled in the dragover event handler.

const dropZone = document.querySelector('#drop-zone');

dropZone.addEventListener('dragover', (event) => {
  // Prevent default to allow drop
  event.preventDefault();
  event.dataTransfer.dropEffect = 'copy';
});

Passing Text and Custom Strings

Text transfer relies on key-value pairs assigned via MIME types. The drag source uses setData() during the dragstart event, and the drop target reads the data using getData() during the drop event.

  1. Setting the Data:

    draggableElement.addEventListener('dragstart', (event) => {
      event.dataTransfer.setData('text/plain', 'Sample text payload');
      event.dataTransfer.setData('text/html', '<strong>Formatted Text</strong>');
    });
  2. Reading the Data:

    dropZone.addEventListener('drop', (event) => {
      event.preventDefault();
      const textData = event.dataTransfer.getData('text/plain');
      console.log('Received text:', textData);
    });

Common MIME types include text/plain, text/html, and text/uri-list. Developers can also define custom MIME types (e.g., application/my-custom-type) to pass serialized JSON strings between elements.

Passing Files to Drop Zones

When users drag files directly from their operating system’s file manager into the browser, the DataTransfer object captures them in two properties: files and items.

Using the files Property

The dataTransfer.files property returns a standard FileList containing File objects. These can be inspected, converted, or uploaded using the FileReader API, fetch(), or FormData.

dropZone.addEventListener('drop', (event) => {
  event.preventDefault();
  
  const files = event.dataTransfer.files;
  for (const file of files) {
    console.log(`File Name: ${file.name}, Size: ${file.size} bytes`);
  }
});

Using the items Property

The dataTransfer.items property provides a DataTransferItemList, offering lower-level access to both files and string data. This is particularly useful for checking file types before reading them or for accessing directories using webkitGetAsEntry().

dropZone.addEventListener('drop', (event) => {
  event.preventDefault();

  if (event.dataTransfer.items) {
    for (const item of event.dataTransfer.items) {
      if (item.kind === 'file') {
        const file = item.getAsFile();
        console.log('Extracted file via items:', file.name);
      }
    }
  }
});

Security Considerations

For security reasons, data stored inside DataTransfer is subject to restrictions based on the event phase. During dragenter and dragover events, the data payload is in a protected mode; scripts can inspect data types (via types) and file counts, but they cannot read the actual string contents or file data using getData() or files. The data only becomes readable once the drop event fires.