
It handles mouse and touch input, drop placeholders, draggable wrappers, optional cloning, and callback-based control during the drag lifecycle.
You can use this library to create drag and drop UI such as kanbans boards, sortable content groups, product pickers, block-based editors, and simple admin layout tools.
Features
- Move elements between custom drop regions.
- Replace dropped elements with target elements.
- Clone items from drag-only source regions.
- Restrict dragging to handle elements.
- Support mouse input on desktop screens.
- Support touch input on mobile devices.
- Refresh draggable items after DOM changes.
- Refresh drop regions after dynamic layout changes.
- Clean up event listeners during teardown.
- Control drag behavior through callbacks.
How to use it:
1. Install Dragster with a package manager and import it into your JS:
# Yarn $ yarn add dragsterjs # NPM $ npm install dragsterjs
import Dragster from 'dragsterjs';
2. You can also directly import the browser module when you host the module file yourself.
<script type="module"> import Dragster from './vendor/dragster.js'; </script>
3. Or load the minified script directly from unpkg and use the global Dragster:
<script src=”https://unpkg.com/dragsterjs/dragster.min.js”></script>
4. Create one or more drop regions and place draggable elements inside them.
<div class="task-lane" aria-label="Backlog tasks"> <article class="task-card">Write docs</article> <article class="task-card">Review UI copy</article> </div> <div class="task-lane" aria-label="Done tasks"> <article class="task-card">Ship homepage</article> </div>
5. Add the required CSS rules. The first rule prevents accidental text selection during dragging. The second rule lets the drop zone under the shadow element receive pointer hover behavior.
[draggable] {
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.dragster-temp {
pointer-events: none;
}6. Initialize Dragster.js with the selectors used in your markup.
const taskDrag = Dragster({
// Select every item that users can drag.
elementSelector: '.task-card',
// Select every region that can receive items.
regionSelector: '.task-lane'
});7. A dashboard layout often needs item swapping instead of normal movement. The option below swaps the dragged block with the target block inside the selected region set.
const widgetDrag = Dragster({
elementSelector: '.dashboard-widget',
regionSelector: '.dashboard-column',
replaceElements: true
});
8. A fixed-height board can break when the script recalculates lane height. This configuration keeps region height under your own CSS control.
const fixedBoardDrag = Dragster({
elementSelector: '.kanban-ticket',
regionSelector: '.kanban-lane',
updateRegionsHeight: false
});
9. Dynamic interfaces often add cards after an API response or form submit. Call update() after you insert new draggable elements into an existing region.
const issueDrag = Dragster({
elementSelector: '.issue-card',
regionSelector: '.issue-column'
});
document.querySelector('#add-issue').addEventListener('click', function () {
const issue = document.createElement('article');
issue.className = 'issue-card';
issue.textContent = 'New support ticket';
document.querySelector('.issue-column').appendChild(issue);
// Re-scan the DOM for new draggable elements.
issueDrag.update();
});
10. Large cards often need a smaller drag handle to prevent accidental movement. The handle class must exist on the element that receives the initial mouse or touch press.
const handleDrag = Dragster({
elementSelector: '.profile-card',
regionSelector: '.profile-row',
dragHandleCssClass: 'profile-card__grip'
});
11. A product shelf can let users add the same item to a cart multiple times. Mark the source region as drag-only and enable cloning.
<div class="product-shelf dragster-region--drag-only"> <article class="shop-item" data-sku="keyboard-pro">Keyboard Pro</article> <article class="shop-item" data-sku="mouse-lite">Mouse Lite</article> </div> <div class="cart-zone" aria-label="Shopping cart"></div>
const cartDrag = Dragster({
elementSelector: '.shop-item',
regionSelector: '.product-shelf, .cart-zone',
dragOnlyRegionCssClass: 'dragster-region--drag-only',
cloneElements: true
});
Real-world Example:
A two-column task board needs markup, CSS, and JavaScript together. Keep each card inside a region before initialization, and load the module after the DOM exists.
<section class="work-board">
<div class="work-lane" aria-label="Open work">
<article class="work-card">Create pricing mockup</article>
<article class="work-card">Fix mobile menu</article>
</div>
<div class="work-lane" aria-label="Completed work">
<article class="work-card">Update footer links</article>
</div>
</section>
<script type="module">
import Dragster from './vendor/dragster.js';
Dragster({
elementSelector: '.work-card',
regionSelector: '.work-lane',
minimumRegionHeight: 120
});
</script>
.work-board {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 16px;
}
.work-lane {
min-height: 120px;
padding: 12px;
border: 1px solid #d7dce2;
border-radius: 8px;
}
.work-card {
margin-bottom: 10px;
padding: 12px;
border: 1px solid #c7ccd4;
border-radius: 6px;
background: #fff;
cursor: grab;
}
[draggable] {
user-select: none;
}
.dragster-temp {
pointer-events: none;
}
A block palette needs cloning because source blocks should stay available after each drop. The source region needs the drag-only class that matches your Dragster.js option.
<div class="builder-layout">
<aside class="block-palette dragster-region--drag-only">
<div class="builder-block">Hero Section</div>
<div class="builder-block">Feature Grid</div>
<div class="builder-block">Newsletter Form</div>
</aside>
<main class="page-canvas" aria-label="Page canvas"></main>
</div>
<script type="module">
import Dragster from './vendor/dragster.js';
const builderDrag = Dragster({
elementSelector: '.builder-block',
regionSelector: '.block-palette, .page-canvas',
dragOnlyRegionCssClass: 'dragster-region--drag-only',
cloneElements: true,
onAfterDragDrop: function (event) {
// clonedTo references the new block placed in the target region.
if (event.dragster.clonedTo) {
event.dragster.clonedTo.dataset.blockId = crypto.randomUUID();
}
}
});
</script>
Configuration Options:
-
elementSelector(String): Selects the elements that Dragster.js should make draggable. The default value is'.dragster-block'. -
regionSelector(String): Selects the drop regions where drag and drop behavior should run. The default value is'.dragster-region'. -
dragHandleCssClass(String|Boolean): Restricts drag start to a specific CSS class when set to a class name. The default value isfalse, so the full element starts the drag. -
replaceElements(Boolean): Switches the dragged element with the drop target instead of moving the dragged element into a placeholder. The default value isfalse. -
cloneElements(Boolean): Clones the dragged element into the target region and keeps the original in place. This option requires a drag-only source region. The default value isfalse. -
updateRegionsHeight(Boolean): Updates region height based on visible elements in each region. The default value istrue. -
minimumRegionHeight(Number): Sets the smallest height that Dragster.js should apply to a region during height updates. The default value is60. -
scrollWindowOnDrag(Boolean): Scrolls the window when the dragged item approaches the top or bottom of the viewport. The default value isfalse. -
dragOnlyRegionCssClass(String): Marks source regions used for clone-only workflows. The default value is'dragster-region--drag-only'. -
wrapDraggableElements(Boolean): Wraps draggable elements in Dragster.js wrapper elements. The default value istrue. -
shadowElementUnderMouse(Boolean): Places the shadow element under the original pointer position instead of centering it on half of its width. The default value isfalse. -
onBeforeDragStart(Function): Runs before a drag starts. Returnfalseto cancel the drag. -
onAfterDragStart(Function): Runs after a drag starts. -
onBeforeDragMove(Function): Runs before each drag move. Returnfalseto cancel the current movement. -
onAfterDragMove(Function): Runs after each drag move. -
onBeforeDragEnd(Function): Runs before a drag ends. Returnfalseto cancel the drop. -
onAfterDragEnd(Function): Runs after a drag ends. -
onAfterDragDrop(Function): Runs after an element has been dropped, replaced, or cloned.
Callbacks receive one Dragster event object through event.dragster.
const auditDrag = Dragster({
elementSelector: '.audit-card',
regionSelector: '.audit-lane',
onBeforeDragStart: function (event) {
const draggedNode = event.dragster.drag.node;
// Return false when your app needs to block this drag.
return !draggedNode?.classList.contains('is-locked');
},
onAfterDragDrop: function (event) {
console.log('Dragged node:', event.dragster.drag.node);
console.log('Drop target:', event.dragster.drop.node);
console.log('Dropped node:', event.dragster.dropped);
console.log('Clone source:', event.dragster.clonedFrom);
console.log('Clone target:', event.dragster.clonedTo);
}
});
The callback object can include these fields.
{
drag: { node },
drop: { node },
shadow: { node, top, left },
placeholder: { node, position },
dropped: node,
clonedFrom: node,
clonedTo: node
}API Methods:
// Re-scan the DOM for draggable elements that match elementSelector. taskDrag.update(); // Re-scan the DOM for drop regions that match regionSelector. taskDrag.updateRegions(); // Remove Dragster.js event listeners before a component or page view is removed. taskDrag.destroy();
Alternatives:
- 10 Best Drag And Drop JavaScript Libraries
- Discover more Drag & Drop JavaScript Libraries
- Draggable/Droppable/Sortable Components In Vanilla JavaScript
- Touch-Friendly JavaScript Drag and Drop Sortable Library
- Lightweight JS Sorting Library with Native HTML5 Drag and Drop
- Mobile-friendly Drag And Drop JavaScript Library – Drog.js
FAQs:
Q: Why does dropping feel wrong or fail over a region?
A: Add the required .dragster-temp { pointer-events: none; } rule. The shadow element can block hover detection when this CSS rule is missing.
Q: Can Dragster.js handle dynamically added cards?
A: Yes. Add the new DOM element, then call instance.update() so the library can re-scan draggable elements.
Q: Can Dragster.js work inside React, Vue, or Angular projects?
A: Yes, but you need to initialize it after the DOM nodes exist. Call destroy() when the component unmounts or the view changes.
Q: Can elements be dragged between two separate Dragster instances?
A: No. Each Dragster instance operates on its own scoped set of regions and elements. Place all participating regions under a single Dragster instance to allow movement between them.
The post Touch-Friendly Drag and Drop Library for Vanilla JS – Dragster.js appeared first on CSS Script.
Discover more from RSS Feeds Cloud
Subscribe to get the latest posts sent to your email.
