HTML draggable Attribute
The HTML draggable attribute is an enumerated attribute and specifies whether the element is draggable or not. Read and see on what elements it can be used.
The HTML draggable attribute is an enumerated attribute that specifies whether an element can be dragged by the user with a pointing device (mouse or touch). It is the entry point to the HTML Drag and Drop API, which lets you move elements, text, files, or custom data from one place in a page to another.
Setting draggable="true" only makes an element pickable. To actually move something and drop it somewhere useful, you also need to handle the drag-and-drop events and carry information through the dataTransfer object — both covered below.
You can use this attribute on any HTML element. It is a part of the Global Attributes, so it works alongside other global attributes such as contenteditable.
Values
The draggable attribute can have the following values:
true— the element can be dragged.false— the element cannot be dragged. Useful for disabling the default dragging of images and links.auto— use the browser's default behavior for that element. In practice this means images and links are draggable, and most other elements are not. Becauseautosimply defers to the default, it is rarely written explicitly; omittingdraggablegives the same result.
<tag draggable="true|false|auto"></tag>Note:
draggableis not a boolean attribute. You must write the value explicitly —draggableon its own ordraggable=""is invalid. Always usedraggable="true"ordraggable="false".
How drag and drop works
A drag-and-drop interaction fires a sequence of events, split between the element being dragged (the source) and the element it is dropped on (the target):
| Event | Fires on | When |
|---|---|---|
dragstart | source | The user starts dragging the element. Set your data here with dataTransfer.setData(). |
drag | source | Repeatedly while the element is being dragged. |
dragenter | target | The dragged element enters a valid drop target. |
dragover | target | Repeatedly while the element is over a drop target. Call preventDefault() here. |
dragleave | target | The dragged element leaves the drop target. |
drop | target | The element is released over the target. Read your data here with dataTransfer.getData(). |
dragend | source | The drag ends (whether it was dropped successfully or cancelled). |
The dataTransfer object
Every drag event exposes event.dataTransfer, the channel used to pass data from the source to the target:
event.dataTransfer.setData(format, data)— store a string duringdragstart. Theformatis usually a MIME type like"text/plain"(older code uses"Text", which still works).event.dataTransfer.getData(format)— read that string back duringdrop.
Because data only becomes available on drop, the typical pattern is to store an element's id (or any identifier) in dragstart, then look it up and move it in drop.
Why preventDefault() is required
By default, most elements are not valid drop targets, so the browser cancels the drop. To opt an element in as a drop zone you must call event.preventDefault() in its dragover handler — this tells the browser "yes, a drop is allowed here." It is also common to call preventDefault() in the drop handler to stop the browser's default action (for example, navigating to a dragged link or opening a dropped file).
If you forget preventDefault() in dragover, the drop event never fires and nothing happens.
Example (inline handlers)
This example uses inline event-handler attributes (ondragstart, ondragover, ondrop). It is concise but mixes JavaScript into the markup:
<!DOCTYPE HTML>
<html>
<head>
<title>Title of the document</title>
<style>
#rectId {
width: 350px;
height: 70px;
padding: 10px;
border: 1px solid #aaaaaa;
}
</style>
<script>
function allowDrop(event) {
event.preventDefault(); // Allow dropping
}
function drag(event) {
// Store the dragged element's ID in the dataTransfer object
event.dataTransfer.setData("text/plain", event.target.id);
}
function drop(event) {
event.preventDefault();
var data = event.dataTransfer.getData("text/plain"); // Retrieve the ID
event.target.appendChild(document.getElementById(data));
}
</script>
</head>
<body>
<div id="rectId" ondrop="drop(event)" ondragover="allowDrop(event)"></div>
<br />
<p id="dragId" draggable="true" ondragstart="drag(event)">
This is a draggable paragraph. Drag this item to the rectangle.
</p>
</body>
</html>Example (modern addEventListener)
For maintainable code, keep the markup clean and attach handlers in JavaScript with addEventListener. This is the recommended approach:
<!DOCTYPE HTML>
<html>
<head>
<title>Title of the document</title>
<style>
#dropzone {
width: 350px;
height: 70px;
padding: 10px;
border: 1px solid #aaaaaa;
}
</style>
</head>
<body>
<div id="dropzone"></div>
<br />
<p id="item" draggable="true">
This is a draggable paragraph. Drag this item to the rectangle.
</p>
<script>
const item = document.getElementById("item");
const dropzone = document.getElementById("dropzone");
// Source: store the dragged element's ID when the drag begins.
item.addEventListener("dragstart", (event) => {
event.dataTransfer.setData("text/plain", event.target.id);
});
// Target: allow dropping by preventing the default handling.
dropzone.addEventListener("dragover", (event) => {
event.preventDefault();
});
// Target: move the element into the drop zone.
dropzone.addEventListener("drop", (event) => {
event.preventDefault();
const id = event.dataTransfer.getData("text/plain");
const dragged = document.getElementById(id);
event.currentTarget.appendChild(dragged);
});
</script>
</body>
</html>Accessibility
The draggable attribute provides no keyboard or screen-reader support on its own — drag and drop is a pointer-only interaction. Users who navigate by keyboard or assistive technology cannot perform a native drag.
If drag and drop is the only way to complete an action, always offer an accessible alternative (for example, "Move up / Move down" buttons, a select menu, or copy/paste). Treat native drag and drop as an enhancement, not the sole path.