npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

drag-and-drop-plugin

v1.0.8

Published

A lightweight drag-and-drop plugin for web applications.

Readme

SWD Drag & Drop

A flexible drag-and-drop plugin using declarative HTML attributes. Supports both position-based and area-based drops.

See Live Demo: https://drag-and-drop-plugin.vercel.app/

Installation

npm i drag-and-drop-plugin

Get Started

Step 1: Enable the plugin in your JavaScript:

import { dragNDropPlugin } from 'drag-and-drop-plugin';

// Enable the drag-and-drop plugin globally
dragNDropPlugin.enablePlugin();

// Call this to disable plugin
// dragNDropPlugin.disablePlugin();

Step 2: Add attributes to your HTML elements.

Making Elements Draggable

Add data-swd-targets to any element to make it draggable:

<!-- This box can be dropped into zones named "inbox" and "archive" -->
<div data-swd-targets="inbox archive" class="draggable-item">
  Drag me anywhere!
</div>

Creating Drop Zones

Add data-swd-zones to create areas that accept drops:

<!-- This accepts drops from elements targeting "inbox" -->
<div data-swd-zones="inbox" class="drop-area" data-swd-mode="area">
  Drop items here
</div>

Container Setup

Wrap your drag-and-drop area with data-swd-space:

<div data-swd-space>
  <!-- All your draggable elements and drop zones go here -->
</div>

Step 3: Handle drop events (optional):

import { isDraggableWithGetter, type DropEventDetail } from 'drag-and-drop-plugin';

// Handle drop events on the “inbox” zone
const inboxZone = document.querySelector<HTMLElement>('[data-swd-zones~="inbox"]');
inboxZone?.addEventListener('swd-drop', 
  (event: CustomEvent<DropEventDetail>) => {
    const droppedElement = event.detail.target;
    const dropPosition = event.detail.dropPos; // "vt", "hl", "ac", etc.
    
    console.log('Element dropped at position:', dropPosition);
  }
);

Essential Attributes Reference

For Draggable Elements

| Attribute | Purpose | Example | |-----------|---------|---------| | data-swd-targets | Required. Zones this element can drop into | "zone1 zone2" | | data-swd-target-drag-point | Restrict dragging to specific handle | "handle" | | data-swd-drag-point | Mark nested child element as drag handle | "handle" |

For Drop Zones

| Attribute | Purpose | Default | Options | |-----------|---------|---------|---------| | data-swd-zones | Required. Which draggables this accepts | - | "zone1 zone2" | | data-swd-mode | How drops are handled | "position" | "position" or "area" | | data-swd-position | Insert orientation (position mode) | "horizontal" | "horizontal" or "vertical" | | data-swd-area | Drop region (area mode) | "cover" | "left", "right", "top", "bottom", "cover" | | data-swd-offset | Spacing between elements & drop indicator | "top:10,bottom:10,right:10,left:10" | Custom pixel values |

For Container Attribute

Represents a container for drag and drop elements.

  • data-swd-space: Captures mouse events in the empty space around drop zones.

Note:

  • You can only drop an element if the target region is visible.
  • If a drop is not possible/allowed on the hovered element, the drop indicator will appear on the nearest valid region allowing drop on that region.

Drop Event

On a successful drop, a CustomEvent named swd-drop is dispatched. The event includes:

  • target: the dragged element
  • dropPos: the drop position. (Possible values: "vt" | "vb" | "hl" | "hr" | "al" | "ar" | "at" | "ab" | "ac")
    • v = vertical, h = horizontal, l = left, r = right, t = top, b = bottom, a = area, c = cover

Example:

import { dragNDropPlugin, isDraggableWithGetter, type DraggableWithGetter, type DropEventDetail } from 'drag-and-drop-plugin';

dragNDropPlugin.enablePlugin(); 

const drag = document.getElementById("drag") as DraggableWithGetter<{ msg: string; type: string }>;
drag.getDragData = () => ({ msg: "hello from drag", type: "complexObject" });

const dropZone = document.getElementById("dropZone");
dropZone?.addEventListener("swd-drop", (event: CustomEvent<DropEventDetail>) => {
  const el = event.detail.target;
  if (isDraggableWithGetter(el)) { // ensures el has getDragData
    console.log("Element dropped on dropZone with data:", el.getDragData(), "at location", event.detail.dropPos);
  }
});

Tip: For safe data transfer, define a getDragData function on draggable elements using the DraggableWithGetter interface. On drop targets, use isDraggableWithGetter to verify that event.detail.target has getDragData before using it.

Full Example

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>drag-and-drop-plugin</title>
<link rel="stylesheet" href="style.css" />
<script type="module" src="./src/main.ts" defer></script>
</head>
<body>

<div>
<div data-swd-space>
  <!-- can be dropped on both "Drop Location 1" & "Drop Location 2" -->
  <div id="drag1" class="box" data-swd-targets="zone1 zone2" data-swd-target-drag-point="handle">
    <div>drag1</div>
    <div class="box-handle" data-swd-drag-point="handle">Drag Me</div>
  </div>

  <!-- can be dropped only on "Drop Location 2" -->
  <div id="drag2" class="box" data-swd-targets="zone2">
    <div>drag2</div>
    Drag me too
  </div>

  <!-- drop zones -->
  <div id="drop1" class="box" data-swd-zones="zone1">
    <div>drop1</div>
    Drop Location 1
  </div>
  <div id="drop2" class="box" data-swd-zones="zone2">
    <div>drop2</div>
    Drop Location 2
  </div>
</div>
<br><br>
<div class="txt">Note: drag1 can be dropped on both drop1 & drop2, while drag2 can only be dropped on drop2</div>
</div>

</body>
</html>
import { dragNDropPlugin, isDraggableWithGetter, type DraggableWithGetter, type DropEventDetail } from 'drag-and-drop-plugin';


dragNDropPlugin.enablePlugin();

window.addEventListener("DOMContentLoaded", () => {
const drag1 = document.getElementById("drag1") as DraggableWithGetter<{ msg: string; type: string }>;
drag1.getDragData = () => ({ msg: "hello from drag1", type: "complexObject" });

const drop1 = document.getElementById("drop1");
drop1?.addEventListener("swd-drop", (event: CustomEvent<DropEventDetail>) => {
  const el = event.detail.target;
  if (isDraggableWithGetter(el)) {
    console.log("Element dropped on drop1 with data:", el.getDragData(), "at location", event.detail.dropPos);
  }
});

const drop2 = document.getElementById("drop2");
drop2?.addEventListener("swd-drop", (event: CustomEvent<DropEventDetail>) => {
  const el = event.detail.target;
  if (isDraggableWithGetter(el)) {
    console.log("Element dropped on drop2 with data:", el.getDragData(), "at location", event.detail.dropPos);
  }
});
});
body {
font-family: monospace;
background-color: black;
color: white;
}

.box {
height: 100px;
width: 100px;
background-color: rgba(255, 255, 255, 0.2);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-family: monospace;
gap: 10px;
margin: 10px;
text-align: center;
border: solid rgba(100,100,100, 0.5);
}

[data-swd-space] {
border: solid grey 1px;
display: flex;
flex-wrap: wrap;
}

#drag1 {
position: relative;
}

.box-handle {
height: 20px;
background-color: green;
}