JSPM

  • Created
  • Published
  • Downloads 2204
  • Score
    100M100P100Q114275F
  • License MIT

React library to add dragging to your apps 😉

Package Exports

  • @neodrag/react
  • @neodrag/react/package.json

Readme

@neodrag/react

One draggable to rule em all

A lightweight React hook to make your elements draggable.

Getting Started

Features

  • 🤏 Small in size - ~5KB, plugin architecture enables tree-shaking
  • 🧩 Plugin-based - Mix and match only what you need
  • Performance - Event delegation, pointer capture, optimized for modern browsers
  • 🎯 React Native - Built for React hooks with useDraggable
  • 🔄 Reactive - useCompartment for reactive plugin updates

Installing

npm install @neodrag/react@next

Usage

Basic usage

import { useRef } from 'react';
import { useDraggable } from '@neodrag/react';

function App() {
    const draggableRef = useRef<HTMLDivElement>(null);
    useDraggable(draggableRef);

    return <div ref={draggableRef}>Hello</div>;
}

With plugins

import { useRef } from 'react';
import { useDraggable, axis, grid } from '@neodrag/react';

function App() {
    const draggableRef = useRef<HTMLDivElement>(null);

    useDraggable(draggableRef, [axis('x'), grid([10, 10])]);

    return <div ref={draggableRef}>Hello</div>;
}

Defining plugins elsewhere with TypeScript

import { useRef } from 'react';
import { useDraggable, axis, bounds, BoundsFrom, type Plugin } from '@neodrag/react';

function App() {
    const draggableRef = useRef<HTMLDivElement>(null);

    const plugins: Plugin[] = [axis('y'), bounds(BoundsFrom.parent())];
    useDraggable(draggableRef, plugins);

    return <div ref={draggableRef}>Hello</div>;
}

Getting drag state

import { useRef, useEffect } from 'react';
import { useDraggable } from '@neodrag/react';

function App() {
    const draggableRef = useRef<HTMLDivElement>(null);
    const dragState = useDraggable(draggableRef);

    useEffect(() => {
        console.log('Position:', dragState.offset);
        console.log('Is dragging:', dragState.isDragging);
    }, [dragState]);

    return <div ref={draggableRef}>Hello</div>;
}

Reactive plugins with useCompartment

import { useRef, useState } from 'react';
import { useDraggable, axis, useCompartment } from '@neodrag/react';

function App() {
    const elementRef = useRef<HTMLDivElement>(null);
    const [currentAxis, setCurrentAxis] = useState<'x' | 'y'>('x');

    const axisCompartment = useCompartment(() => axis(currentAxis), [currentAxis]);

    useDraggable(elementRef, () => [axisCompartment]);

    return (
        <div>
            <div ref={elementRef}>Current axis: {currentAxis}</div>
            <button onClick={() => setCurrentAxis(currentAxis === 'x' ? 'y' : 'x')}>Switch Axis</button>
        </div>
    );
}

Read the docs

Credits

Inspired by react-draggable, but with a modern plugin architecture and optimized for performance.

License

MIT License © Puru Vijay