Movatterモバイル変換


[0]ホーム

URL:


  1. Web
  2. Web APIs
  3. HTML Drag and Drop API
  4. File drag and drop

File drag and drop

As mentioned onthe landing page, the Drag and Drop API simultaneously models three use cases: dragging elements within a page, dragging data out of a page, and dragging data into a page. This tutorial demonstrates the third use case: dragging data into a page. We will be implementing a basic drop zone that allows the user to drop image files from the user's operation system file explorer and displays them on the page. For users who can't or don't want to use drag and drop, we also provide the alternative functionality of file selection via an<input> element.

Basic page layout

Because we want to allow normal<input> file selection as well, it makes sense for the drop zone to be backed by an<input> element so that we can simultaneously drag into it and click on it. We take advantage of a common trick, which is to make the<input> invisible, and use its associated<label> to interact with the user instead, because<label> elements are much easier to style. We also add the elements for previewing the dropped images.

html
<label>  Drop images here, or click to upload.  <input type="file" multiple accept="image/*" /></label><ul></ul><button>Clear</button>

We style the label element to visually indicate the element is a drop zone, and hide the file input.

css
body {  font-family: "Arial", sans-serif;}#drop-zone {  display: flex;  align-items: center;  justify-content: center;  width: 500px;  max-width: 100%;  height: 200px;  padding: 1em;  border: 1px solid #cccccc;  border-radius: 4px;  color: slategray;  cursor: pointer;}#file-input {  display: none;}#preview {  width: 500px;  max-width: 100%;  display: flex;  flex-direction: column;  gap: 0.5em;  list-style: none;  padding: 0;}#preview li {  display: flex;  align-items: center;  gap: 0.5em;  margin: 0;  width: 100%;  height: 100px;}#preview img {  width: 100px;  height: 100px;  object-fit: cover;}

By virtue of us using the<label> and<input> elements, no additional JavaScript is needed to implement the file selection UX. We now focus on file dropping and the subsequent processing of the dropped files.

Declaring the drop target

Our drop target is the<label> element. As thetarget element, it listens to thedrop event to process the dropped file.

js
const dropZone = document.getElementById("drop-zone");dropZone.addEventListener("drop", dropHandler);

For file dropping, the browser may process them by default (such as opening or downloading the file) even when the file is not dropped into a valid drop target. To prevent this behavior, we also need to listen for thedrop event onwindow and cancel it. We take care to only handle the event only if a file is being dragged; if it's something else, such as a link, we still use the default behavior. If the dragged item is a non-image file, we still handle the event, but provide feedback to the user that it is not allowed.

js
window.addEventListener("drop", (e) => {  if ([...e.dataTransfer.items].some((item) => item.kind === "file")) {    e.preventDefault();  }});

In order for thedrop event to fire, the element must also cancel thedragover event. Because we are listening fordrop onwindow, we need to cancel thedragover event for the wholewindow as well. We also setDataTransfer.dropEffect tonone if the file is not an image or not dragged to the correct place.

js
dropZone.addEventListener("dragover", (e) => {  const fileItems = [...e.dataTransfer.items].filter(    (item) => item.kind === "file",  );  if (fileItems.length > 0) {    e.preventDefault();    if (fileItems.some((item) => item.type.startsWith("image/"))) {      e.dataTransfer.dropEffect = "copy";    } else {      e.dataTransfer.dropEffect = "none";    }  }});window.addEventListener("dragover", (e) => {  const fileItems = [...e.dataTransfer.items].filter(    (item) => item.kind === "file",  );  if (fileItems.length > 0) {    e.preventDefault();    if (!dropZone.contains(e.target)) {      e.dataTransfer.dropEffect = "none";    }  }});

Note:dragstart anddragend events are not fired when dragging a file into the browser from the OS. To detect when OS files are dragged into the browser, usedragenter anddragleave.This means that it is not possible to usesetDragImage() to apply a custom drag image/cursor overlay when dragging files from the OS — because the drag data store can only be modified in thedragstart event. This also applies tosetData().

Processing the drop

Now we implement thedropHandler by using thegetAsFile() method to access each file. Then your application can decide how to process this file using theFile API. Here we just display them on the page; in practice, you probably want to eventually upload them to the server as well.

js
const preview = document.getElementById("preview");function displayImages(files) {  for (const file of files) {    if (file.type.startsWith("image/")) {      const li = document.createElement("li");      const img = document.createElement("img");      img.src = URL.createObjectURL(file);      img.alt = file.name;      li.appendChild(img);      li.appendChild(document.createTextNode(file.name));      preview.appendChild(li);    }  }}function dropHandler(ev) {  ev.preventDefault();  const files = [...ev.dataTransfer.items]    .map((item) => item.getAsFile())    .filter((file) => file);  displayImages(files);}

Adding the same behavior to the input

The above is the whole data flow for the drag and drop; now we need to wire thedisplayImages() function to the file input as well.

js
const fileInput = document.getElementById("file-input");fileInput.addEventListener("change", (e) => {  displayImages(e.target.files);});

Clear button

Finally we add a way to clear the preview area. We useURL.revokeObjectURL() to release the memory used by the image objects.

js
const clearBtn = document.getElementById("clear-btn");clearBtn.addEventListener("click", () => {  for (const img of preview.querySelectorAll("img")) {    URL.revokeObjectURL(img.src);  }  preview.textContent = "";});

Result

See also

Help improve MDN

Learn how to contribute

This page was last modified on byMDN contributors.


[8]ページ先頭

©2009-2025 Movatter.jp