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

@bitboss-dev/vue-dnd

v0.0.2

Published

A lightweight **(4kb)**, performant drag and drop library for Vue 3.

Readme

Vue DnD

A lightweight (4kb), performant drag and drop library for Vue 3.

Features

  • 🚀 Vue 3 & Composition API - Built specifically for Vue 3 with script setup syntax
  • 📦 TypeScript First - Full TypeScript support with comprehensive type definitions
  • 🎯 Namespace-based - Avoid conflicts between separate drag operations. A subject within the to-do-list namespace will exclusively interact with events on targets sharing the same namespace. Seamlessly.
  • 🔄 Deduplicated - Built-in deduplication. Only the topmost element will receive the event but you can change that if you want.
  • 🎨 Visual Feedback - Built-in clone dragging with smooth animations
  • 🔧 Flexible - Make it as granular as you need.
  • 📱 Touch Support - Works on mobile devices with touch events

Installation

npm install @bitboss-dev/vue-dnd

Quick Start

<template>
  <div class="app">
    <!-- Draggable Item -->
    <div
      ref="draggableItem"
      class="draggable-item"
      :class="{ 'draggable-item--dragging': isDragging }"
    >
      Drag me!
    </div>

    <!-- Drop Zone -->
    <div
      ref="dropZone"
      class="drop-zone"
      :class="{ 'drag-zone--active': isOver }"
    >
      Drop here
    </div>
  </div>
</template>

<script setup lang="ts">
import { useTemplateRef } from 'vue'
import {
  useDragSubject,
  useDragTarget,
  useDragClone,
} from '@bitboss-dev/vue-dnd'

const draggableItem = useTemplateRef('draggableItem')
const dropZone = useTemplateRef('dropZone')

// Set up drag subject (the element to be dragged)
const { isDragging, attributes } = useDragSubject(
  draggableItem,
  'my-drag-namespace'
)

// Set up drop target
const { isOver } = useDragTarget(dropZone, 'my-drag-namespace')

// Create visual clone during drag
useDragClone(draggableItem, attributes)
</script>

Why and how

This library is designed for a straightforward task: dragging an item from point A to point B. Once you release the dragged item, everything resets. You can't continue dragging the item indefinitely; it either reaches the target or resets. This approach addresses the most basic use case.

The API is clear and easy to use.

Steps to get started:

  • Define a namespace. For example, if you're dragging a user card into a contact list, use a user-contacts namespace.
  • Create a card to act as the draggable item and apply the composable with the specified namespace.
  • Set up a surface as the drop target and apply the composable with the same namespace.
  • That's it!

API Reference

useDragAttributes low level helper to track drag events.

Provides reactive drag attributes and a basic flag. Useful for low-level drag tracking or custom drag-and-drop implementations.

function useDragAttributes(
  elementRef: MaybeRefOrGetter<unknown>,
  options?: DragAttributesOptions
): {
  attributes: Ref<Attributes>
  isDragging: Ref<boolean>
}

Parameters

  • elementRef - Vue template ref or DOM element to track for pointer events.
  • options - Optional configuration object

Options

type DragAttributesOptions = {
  // when the element is unmounted clears all document event listeners.
  // Set to false to continue dragging if the original container is removed
  autoCleanup?: boolean
  onPointerDown?: (event: PointerEvent) => void
  onPointerMove?: (event: PointerEvent) => void
  onPointerUp?: (event: PointerEvent) => void
}

Returns

  • attributes - Reactive object containing position and size data
  • isDragging - Boolean indicating if element is currently being dragged

useDragSubject Creates a draggable element that can be dragged around the page.

The subject receives the same events of the target so you can act with the callbacks onEnter, onOver, onLeave, onDrop.

Everything is lazy, no events are fired or listened to unless they are useful.

function useDragSubject<T = unknown>(
  elementRef: MaybeRefOrGetter<unknown>,
  namespace: NameSpace,
  item?: T,
  options?: DragSubjectOptions<T>
): {
  attributes: Ref<Attributes> // See later definition
  isDragging: Ref<boolean>
  isOver: Ref<boolean>
}

Parameters

  • elementRef - Vue template ref to the draggable element
  • namespace - Unique identifier that links the subject to its drop area.
  • item - Optional data to pass with drag events
  • options - Configuration options

Options

type DragSubjectOptions<T = unknown> = {
  /**
   * Automatically cleans up event listeners when the element is unmounted.
   * Set to false to keep listeners active even if the original container is removed.
   * @default true
   */
  autoCleanup?: boolean

  /**
   * Callback function triggered when the draggable element enters a drop target.
   * @param data  - The data associated with the drag event.
   * @param event - The original event object.
   */
  onEnter?: ClientEventHandler<T>

  /**
   * Callback function triggered when the draggable element is moved over a drop target.
   * @param data - The data associated with the drag event.
   * @param event - The original event object.
   */
  onOver?: ClientEventHandler<T>

  /**
   * Callback function triggered when the draggable element is dropped on a drop target.
   * @param data - The data associated with the drag event.
   * @param event - The original event object.
   */
  onDrop?: ClientEventHandler<T>

  /**
   * Callback function triggered when the draggable element leaves a drop target.
   * @param data - The data associated with the drag event.
   * @param event - The original event object.
   */
  onLeave?: ClientEventHandler<T>
}

Returns

  • attributes - Reactive object containing position and size data
  • isDragging - Boolean indicating if element is currently being dragged
  • isOver - Boolean indicating if element is over a drop target

useDragTarget

Creates a drop target area. It fires the same events of the subject. you can act with the callbacks onEnter, onOver, onLeave, onDrop.

Everything is lazy, no events are fired or listened to unless they are useful

function useDragTarget<T = unknown>(
  elementRef: MaybeRefOrGetter<unknown>,
  namespace: NameSpace,
  options?: UseDragTargetOptions<T>
): {
  isDragging: Ref<boolean>
  isOver: Ref<boolean>
  item: Ref<T | null>
}

Parameters

  • elementRef - Vue template ref to the drop target element
  • namespace - Must match the namespace of the drag subject
  • options - Configuration options

Options

type UseDragTargetOptions<T> = {
  onEnter?: ClientEventHandler<T>
  onOver?: ClientEventHandler<T>
  onLeave?: ClientEventHandler<T>
  onDrop?: ClientEventHandler<T>
  nested?: boolean // Default: true - when true only the topmost surface area will eb reactive
}

Returns

  • isDragging - Boolean indicating if any item in this namespace is being dragged
  • isOver - Boolean indicating if an item is over this target
  • item - The currently dragged item data

useDragClone

Creates a visual clone that follows the cursor during drag operations.

function useDragClone(
  elementRef: MaybeRefOrGetter<unknown>,
  attributes: MaybeRefOrGetter<Attributes>,
  options?: Options
): {
  clone: Ref<HTMLElement | null>
  removeClone: () => void
}

Parameters

  • elementRef - Vue template ref to the original element
  • attributes - Attributes from useDragSubject
  • options - Configuration options

Options

type Options = {
  cloneClass?: string // Default: 'clone'
}

Types

Attributes

type Attributes = {
  // The container rect data
  container: {
    x: number
    y: number
    width: number
    height: number
  }
  // Event data
  event: {
    x: number
    y: number
  }
  // Projected data of the container after translating it (used by the clone)
  translated: {
    x: number
    y: number
  }
  // The x, y delta from the initial event
  delta: {
    x: number
    y: number
  }
}

Best Practices

  1. Use Descriptive Namespaces - Choose meaningful names like 'user-contact-list' or 'document-file-upload'
  2. Handle Cleanup - The library automatically cleans up event listeners
  3. Touch Support - The library handles touch events automatically

License

MIT License - see LICENSE file for details.