0

When using the HTML Drap and Drop API, how can I change what the cursor looks like?

It seems to be using the default no-drop while not over a dropable zone as well as some other ones (that I can't find in the list of standard cursors) while over a droppable zone. As I'm implementing a game and would like to be able to drag & drop items onto each other, this API is perfect for this, execpt I cannot control what the cursor looks like it seems. And the default browser cursors are very different from my custom cursor(s) that I have throughout the game so I'd like to be able to modify them.

I found this answer, but I will not add jquery to the project just for this.

Is there a css pseudoelement or some script way (e.g. by modifying the drag event) that I can use? I've looked at the Drag & Drop API documentation but to no avail.

I'd be happy if I can just hide the cursor altogether. While not ideal, I could use that to then place a custom cursor on the screen using js.

Edit: This is what the cursors I'm trying to change look like. They appear (like this or similar) once you started dragging - the first one if you're above a dropzone, the second one if you're not.
You can try it by marking any text in this post and try to drag it around the page. In the search bar or answer field you'll get a version of the first cursor, everywhere else you'll get the second.

a default cursor with a dotted rectangle at its tail a red circle with a diagonal line, indicating something forbidden

3
  • In your drag start handler, simply change the CSS for your cursor, then in the dropped handler change the cursor css back to your desired style. Commented Apr 9 at 16:58
  • do you mean the CSS properties cursor: grab and cursor: grabbing? Commented Apr 9 at 17:00
  • @RahulMehta no, that's not what I mean. Unfortunately I cannot take screenshots where my mouse is visible, but I'll attach some images to my post that might clarify things.
    – Plagiatus
    Commented Apr 10 at 7:53

1 Answer 1

1

EDIT: OP wants the default behavior built in to the Drag and Drop API to show the "not allowed" ICON below the cursor when the dragging element is not over an allowed drop zone.

You must use a specific elements ID or class to tell JS exactly what is being dragged and what is being targeted as a viable drop zone.

EXAMPLE:

  addEventListener('dragstart', (event) => {}
  // or  
  addEventListener('dragleave', (event) => {} 
  // this is the same as 
  window.addEventListener('dragstart', (event) => {}
  window.addEventListener('dragleave', (event) => {}

So in case if you use the window version of an event listener for both or more events used in drag and drop API, JS will not be able to tell where the not allowed area is. We must specify the exact element being dragged and the exact element that will allow a drop to get the not allowed icon to accompany the cursor when dragged.

const items = document.querySelectorAll('.items');
const dropzone = document.querySelector('.dropzone');

items.forEach((item, j) => {

  let dragged = null;
  // we must define the element we are dragging
  // which in this case is one of our items array of elements => item
  item.addEventListener("dragstart", (event) => {
    dragged = event.target;
  });

  // now for the dragover and drop events we must define the specific
  // element we wish to drop and/or drag over for the built in "not allowed"
  // icon to properly show
  
  dropzone.addEventListener("dragover", (event) => {
    // prevent default to allow drop
    event.preventDefault();
    // are we over the drag dropzone? 
    // is dragged not null?
    if (event.target.classList.contains("dropzone") && dragged) {
      // add a classlist to indicate where to drop the draggable element
      event.target.classList.add('drag-over');
    }
  });

  dropzone.addEventListener("drop", (event) => {
    event.preventDefault();
    // move dragged element to the selected drop target
    if (event.target.classList.contains("dropzone") && dragged) {
      // remove the draggable element from its parent element
      dragged.parentNode.removeChild(dragged);
      // append draggable element to the dropzone element
      event.target.appendChild(dragged);
      // remove classList drag-over upon drop event
      event.target.classList.remove('drag-over');
      // set dragged variable to null
      dragged = null;

    }

  });

})
.drag-over {
  box-shadow: 0 0 2px 3px rgb(0, 0, 0);
}

#inv-overlay {
  position: absolute;
  top: 50px;
  left: 200px;
  display: inline-block;
  width: 100px;
  height: 100px;
  transition: opacity 0.2s linear;
  background-color: red;
  font-size: 1rem;
}

.items {
  width: max-content;
}

/* SETTING YOUR CURSOR STYLE ON HOVER */
.items:hover {
  cursor: move;
}

/* SETTING YOUR CURSOR STYLE ON ACTIVE */
.items:active {
  cursor: grabbing;
}
<div id="inv-overlay" class="dropzone"></div>
<div class="items" draggable="true">One</div>
<div class="items" draggable="true">Two</div>
<div class="items" draggable="true">Three</div>

EDIT 2: Op wants to change the default ICON that follows the drag and drop API, however these are sort of locked in as dataTransfer types and have a list of effectAllowed = MDN on Data transfer effects that are allowed

8
  • Thank you for your reply. Unfortunately the actual cursors that I'm after, namely the ones it shows once you grabbed the item and started moving your mouse (the default cursor with a little rectangle below it while above a dropzone, the no-drop cursor outside of a dropzone) remain unchanged.
    – Plagiatus
    Commented Apr 10 at 7:49
  • I see what you're looking for now. The reason my first example was not working for you is because I was using the window element as the listeners. I have updated the answer to be more poignant by adding the items as the drag-start events and the dropzone as the targeted events. See my updated answer. Commented Apr 11 at 0:16
  • @Plagiatus see my edited answer pls. Lemmie know if this does the trick for you. Commented Apr 11 at 3:17
  • Hi, thank you for the update. Unfortunately it seems we still talked past each other, my issue isn't when the "not allowed" cursor is shown, but that I want to CHANGE what the not-allowed (and the "you can drop here" cursor) look like.
    – Plagiatus
    Commented Apr 11 at 7:51
  • 1
    First of all, thank you for your continued efforts. Yes, I'm looking to change the default cursor icon that accompanies the drag&drop functionalities. It seems that the drag&drop API might not cover this usecase at this time. Looks like I'll have to either use a library (or write my own little thing for my particular usecase). Thank you a lot anyways.
    – Plagiatus
    Commented Apr 15 at 13:04

Not the answer you're looking for? Browse other questions tagged or ask your own question.