DEV Community

Cover image for Make Drag & Drop + DropZone with interact.js + reactjs
0xkoji
0xkoji

Posted on

Make Drag & Drop + DropZone with interact.js + reactjs

What is interact.js

https://interactjs.io/

JavaScript drag and drop, resizing and multi-touch gestures with inertia and snapping for modern browsers (and also IE9+).JavaScript drag and drop, resizing and multi-touch gestures with inertia and snapping for modern browsers (and also IE9+).JavaScript drag and drop, resizing and multi-touch gestures with inertia and snapping for modern browsers (and also IE9+).

GitHub logo taye / interact.js

JavaScript drag and drop, resizing and multi-touch gestures with inertia and snapping for modern browsers (and also IE9+)

interact.js

JavaScript drag and drop, resizing and multi-touch gestures with inertia and snapping for modern browsers (and also IE9+)

Gitter jsDelivr Build Status

Features include:

  • inertia and snapping
  • multi-touch, simultaneous interactions
  • cross browser and device, supporting the desktop and mobile versions of Chrome, Firefox and Opera as well as Internet Explorer 9+
  • interaction with SVG elements
  • being standalone and customizable
  • not modifying the DOM except to change the cursor (but you can disable that)

Installation

  • npm: npm install interactjs
  • jsDelivr CDN: <script src="https://cdn.jsdelivr.net/npm/interactjs/dist/interact.min.js"></script>
  • unpkg CDN: <script src="https://unpkg.com/interactjs/dist/interact.min.js"></script>
  • Rails 5.1+:
    1. yarn add interactjs
    2. //= require interactjs/interact
  • Webjars SBT/Play 2: libraryDependencies ++= Seq("org.webjars.npm" % "interactjs" % version)

Typescript definitions

The project is written in Typescript and the npm package includes the type definitions, but if you need the typings alone, you can install them with:

npm install --save-dev @interactjs/types

Documentation

http://interactjs.io/docs

Example

var pixelSize = 16;
interact('.rainbow-pixel-canvas')
Enter fullscreen mode Exit fullscreen mode

Recently I've worked on Electron + reactjs for h/w(hardware). Then I needed to implement gestures such as long press, swipe, scroll up/down, and drag & drop.

Actually, I thought if I used hammerjs, it would be easy, but actually I gave up using that since it seemed that hammerjs's development wasn't active any more unfortunately.

The last tag was 2016, for personal development that would be fine but the project isn't a personal project so I gave up using that. Then I was doing some research on Openbase.

I checked a few libraries and created a compare list to get feedback from team members. Then we decided to use interact.js because the number of starts is good and it supports gestures the design team requested. In addition, its document is well-organized and we can use it with typescript easily.

docs
https://interactjs.io/docs/

In this article, I will introduce dropzone ui with interact.js + react hooks.

useDrag.ts
https://interactjs.io/docs/draggable/

If you want to use vanillajs, you can use the sample code directly.

import React from "react";
import interact from "interactjs";

type Partial<T> = {
  [P in keyof T]?: T[P];
};

const initialPosition = {
  width: 100,
  height: 100,
  x: 0,
  y: 225
};

export const useDraggable = (
  position: Partial<typeof initialPosition> = initialPosition
) => {
  const [elementPosition, setElementPosition] = React.useState<
    typeof initialPosition
  >({
    ...initialPosition,
    ...position
  });

  const [isEnabled, setIsEnabled] = React.useState<boolean>(true);

  const interactiveRef = React.useRef(null);

  let { x, y, width, height } = elementPosition;

  const enable = () => {
    interact((interactiveRef.current as unknown) as HTMLElement)
      .draggable({
        modifiers: [],
        inertia: false
      })
      .on("dragmove", (event) => {
        x += event.dx;
        y += event.dy;

        setElementPosition({
          width,
          height,
          x,
          y
        });
      });
  };

  const disable = () => {
    interact((interactiveRef.current as unknown) as HTMLElement).unset();
  };

  React.useEffect(() => {
    if (isEnabled) {
      enable();
    } else {
      disable();
    }
    return disable;
  }, [isEnabled]);

  return {
    ref: interactiveRef,
    style: {
      transform: `translate3D(${elementPosition.x}px, ${elementPosition.y}px, 0)`,
      width: `${elementPosition.width}px`,
      height: `${elementPosition.height}px`,
      position: "absolute" as React.CSSProperties["position"],
      touchAction: "none"
    },
    position: elementPosition,
    isEnabled,
    enable: () => setIsEnabled(true),
    disable: () => setIsEnabled(false)
  };
};
Enter fullscreen mode Exit fullscreen mode

App.tsx
https://interactjs.io/docs/dropzone/

import { useRef } from "react";
import interact from "interactjs";
import "./styles.css";
import { useDraggable } from "./hooks/useDraggable";

export default function App() {
  const targetRef = useRef(null);
  const draggable = useDraggable();

  // dropzone
  if (targetRef?.current) {
    interact((targetRef.current as unknown) as HTMLElement)
      .dropzone({
        accept: ".test",
        overlap: 0.75
      })

      .on("dropactivate", (event: Interact.InteractEvent) => {
        event.target.classList.add("drop-active");
      })

      .on("dragenter", (event: Interact.InteractEvent) => {
        console.log("dragenter");
        const draggableElement = event.relatedTarget;
        const dropzoneElement = event.target;
        dropzoneElement.classList.add("drop-target");
        draggableElement?.classList.add("can-drop");
        if (draggableElement) {
          draggableElement.style.color = "#fff";
          draggableElement.textContent = "release me";
        }
      })

      .on("dragleave", (event: Interact.InteractEvent) => {
        const draggableElement = event.relatedTarget;
        const dropzoneElement = event.target;
        dropzoneElement.classList.remove("drop-target");
        draggableElement?.classList.remove("can-drop");
        if (draggableElement) {
          draggableElement.textContent = "dragging me";
        }
      })

      .on("drop", (event: Interact.InteractEvent) => {
        const draggableElement = event.relatedTarget;
        if (draggableElement) {
          draggableElement.style.color = "#fff";
          draggableElement.textContent = "hello world";
        }
      })

      .on("dropdeactivate", (event: Interact.InteractEvent) => {
        event.target.classList.remove("drop-active");
        event.target.classList.remove("drop-target");
      });
  }

  return (
    <div className="App">
      <h1>interactjs samples</h1>
      <div className="test" ref={draggable.ref} style={draggable.style}>
        <p>drag me</p>
        <p>
          {`x: ${draggable.position.x.toFixed(0)}`}
          {`y: ${draggable.position.y.toFixed(0)}`}
        </p>
      </div>
      <div className="dropzone" ref={targetRef}>
        dropzone
      </div>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

Top comments (7)

Collapse
 
marklai1998 profile image
Mark Lai

Actually for react I would suggest dndkit.com/

Collapse
 
0xkoji profile image
0xkoji

Thank you for your suggestion. I will try that in the future.
I'm using interact.js because I need other gestures for an Electron app 😂

Collapse
 
piggov profile image
Bonny Piggov

So much "JavaScript drag and drop, resizing and multi-touch gestures with inertia and snapping for modern browsers (and also IE9+)" 😵‍💫

Collapse
 
0xkoji profile image
0xkoji

Yeah, that is true.
But fortunately I do need to care about only chrome since I'm working on Electron app 😆

Collapse
 
liorgrossman profile image
Lior Grossman

Great to see Openbase helped you in your research!

Collapse
 
0xkoji profile image
0xkoji

Thank you for such an awesome product!

Collapse
 
techtitans0101 profile image
TechTitans0101

Thanks @0xkoji for the informative tips.

Open source is essential for application developers. It is unfortunate that Open Base has shut down. While searching for alternate, came across kandi from Open Weaver. It helps developers find code snippets, packages, libraries and solutions from millions of assets.
Thanks to such tools for support to the open source community. Happy coding!