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 🙏

© 2025 – Pkg Stats / Ryan Hefner

draggables

v0.2.2

Published

Draggable elements.

Downloads

266

Readme

License: MIT ts Build Status

draggables

Draggable elements.

Basic Usage

$ npm install draggables
<!-- HTML -->
<body>
   <div data-drag-role="draggable"></div>
</body>
// js / ts
import {draggables} from 'draggables';

draggables(contextElm, options);

Section Links:

Context Element

Default - document.body

NOTE: The context element is not necessarily a draggable element.

At creation, passing an element to the draggables(ctxElm) function binds a single event listener to the passed in element. This starts listening to pointerdown events on draggable elements within that context element. If no element was passed in at creation the default context element will be the <body> element.

Many times the context element would be the immediate parent of the draggable elements, the "board" of the "stickynotes". If you have more than one "board" you can either make a single context for all off them (a mutual ancestor or the <body>) or prefer to work with multiple instances/contexts.

Things to consider:

  1. There's one Draggables instace per context element.
  2. Each instance/context binds its own pointerdown event listener.
  3. Each context is the boundary element to its draggable elements (by default).

Boundary Element

To prevent users from dragging an element off-screen and being unable to retrieve it, a boundary element is always defined.

By default, the <body> element acts as the global movement container for all draggable elements. However, you can designate a different element as the boundary of its descendant draggable elements by adding the data-drag-zone attribute to it.

So a draggable element's dragging zone is its closest parent with the data-drag-zone attribute or the <body> element.

Data Attributes

Using different data attributes you can control the dragging behavior.

To make an element "draggable" set its data-drag-role attribute to "draggable".

  • data-drag-zone - set this attribute (key only, no value) on the element you want to define as the boundary element of its descendant draggable elements (see Boundary Element).
  • data-drag-role = "draggable" | "grip"
    • "draggable" - Makes the element draggable.
      Can be used together with:
      • data-drag-axis = "x" | "y"
        By default you can drag elements freely on both axes. You can Limit an element's movement to a single axis.

        • "x" - Limit dragging movment along the x axis.
        • "y" - Limit dragging movment along the y axis.
      • data-drag-disabled

        • "true" - Disables dragging
        • "false" - Enables dragging

        Set this attribute when you need to toggle draggability of a draggable element.
        This toggles draggability of a single draggable element. If you want to disable all draggables in a context see .disable() below.

    • "grip" - The element becomes the handle of its closest draggable element. When used, draggable elements can only be dragged when grabbed by their grip element. A grip must be a descendant of a draggable element (throws an error when it's not).

Example:

<div
   class="card"
   data-drag-role="draggable"
   data-drag-axis="x"
   data-drag-disabled="false"
>
   <div class="card-title" data-drag-role="grip">
      Grab here!
   </div>
   <div class="card-body">
      Grab the title to move the card
   </div>
</div>

"read-only" data attributes

Not actually read-only attributes per se but you probably should not change them.

data-drag-active (key only attribute)

While dragging an element it is set with a "read-only" data attribute: data-drag-active . It is removed on drop. This is mostly for styling purposes.

[data-drag-active] {
   background-color: yellow;
}

data-drag-position="x,y"

Elements are moved around using CSS translate(x, y) which sets a relative position to an element's original-natural position. When dropping an element its [x,y] position is saved as value of the data-attribute data-drag-position="x,y". This position will be used as the new starting point for the following drag event.

Instance API

draggables(contextElement, options)

arguments

  • contextElement: HTMLElement - optional. See Context Element section above.
  • options: DraggablesOptions - optional. The instance's configuration object, applied for all draggable elements under the context element:
    • padding: number - Blocks dragStart if the draggable element was grabbed by its edge within this number of pixels. Default is 0.
    • cornerPadding: number - Blocks dragStart if the draggable element was grabbed by its corner within this number of pixels. Default is 0.
draggables();             // -->  <body>
draggables({padding: 8}); // -->  <body>
draggables(myElm);
draggables(myElm, {padding: 8});

The padding options are for dealing with draggable elements that are also resizable (by grabbing their corners/edges).

Returns a Draggables instance:

const d = draggables();

It has the following methods:

.enable() / .disable()

Toggle draggability for all draggable elements within the context. When disabled, the main element gets a 'drag-disabled' classname.

const d = draggables();
// draggability is enabled on construction

d.disable();
d.enable();

Note: Calling .disable() on an instance disables draggability for all draggable elements withing the context element. You can disable specific draggable elements using the disable data attribute. See Data Attributes.

.on(eventName, callback) / .off(eventName)

Start and stop listening to drag events:

  • 'grab' - fires on pointerdown on a draggable element.
  • 'dragStart' - drag started, fires on the first pointermove on a draggable element (after pointerdown).
  • 'dragging' - dragging around, fires on every pointermove except the first one.
  • 'dragEnd' - dragging ended, fires on pointerup.

A Draggables instance can only hold a single event listener for each event (unlike an EventEmitter):

const doSomething = () => {...}
const doSomethingElse = () => {...}
const stopDoingThing = () => {...}

const d = draggables()
   .on('dragStart', doSomething)     // <-- this is replaced
   .on('dragStart', doSomethingElse) // <-- by this (same event)
   .on('dragEnd', stopDoingThing)

d.off('dragStart');

Event Handlers
The event handlers get called with a DragEventWrapper object which holds 3 properties:

  • ev - the vanilla pointer event (type PointerEvent)
  • elm - the draggable element, which is not always the ev.target (type HTMLElement),
  • relPos - the draggable element's relative position (in pixels), that is, relative to its pre-drag position (type [x: number, y: number])
draggables().on('dragging', (dragEv: DragEventWrapper) => {
   console.log(
      dragEv.elm,       // e.g. <div data-drag-role="draggable">
      dragEv.ev.target, // e.g. <div data-drag-role="grip">
      dragEv.relPos     // e.g. [3, -8] (on 'grab' events it's always [0,0])
   );
});

.destroy()

Kills the Draggables instance for good, unbinds event listeners, releases element references. Once destroyed, an instance cannot be revived. Use it when the context element is removed from the DOM.