dnd-kit

A modular toolkit for building drag & drop interfaces for React

Crash Course!

What

What is dnd kit

"A modular, lightweight, performant, accessible and extensible drag & drop toolkit for React."

Stats

No Item Description
1. Total Commits 259
2. Last Commit 20 days ago
3. Opened Issues 74 out of 155
4. Opened Pull Requests 11 out of 122 closed
5. Total Stars 2.7k
6. Total Fork 96
7. First Public Release 3rd Jan 2021 (v1.0.0)
8. Latest version v3.1.1

Contributers

Why

Motivation

  • Drag & Drop functionality is important for an interactive & user friendly user interface
     
  • Current solutions are 
    • too difficult to use
    • not flexible for many uses cases
    • not modular and customizable enough

Comparing to Existing library - Stats

No Item react-dnd react-beautiful-dnd (rbd) dnd-kit
1. Owner facebook atlassian shopify
2. Total Commits 2,170 785 259
3. Last Commit 3 days ago 2 months ago 20 days ago
4. Opened Issues 243 out of 1,233 399 out of 985 74 out of 155
5. Opened Pull Requests 8 out of 1,810  66 out of 852  11 out of 122 
6. Total Stars 16.2k 24.5k 2.7k
7. Total Fork 1.7k 1.8k 96
8. First Public Release 19 May 2015 (v1.0.0) 11 Aug 2017 (v1.0.1) 3rd Jan 2021 (v1.0.0)
9. Latest version v14.0.3 v13.1.0 v3.1.1

Comparing to Existing library - Overview

No Item react-dnd rbd dnd-kit
1. Use Cases ❤️ Anything List, Kaban ❤️ Anything
2. Learning Curve High ❤️ Low ❤️ Low
3. Flexibility ❤️ High Low ❤️ High 
4. Sensor/Backend HTML5 ❤️ Pointer, Mouse, Touch, Keyboard ❤️ Pointer, Mouse, Touch, Keyboard
5. Performance Low ❤️ High ❤️ High
6. Accessibility Low ❤️ High ❤️ High
7. Modularity
 - Styling/ Animation
 - Collision Detection
 - Overlay/Constrains
 - Drag Handles
 - Presets 
Low Medium ❤️ High

Backend / Sensors

  • dnd-kit is not using HTML5 Drag and Drop API by design since it does not support:
    • touch devices / keyboard
    • lock dragging / bounds to container
    • custom collision detection strategies
    • dragged item preview
    • performance/accessibility improvements
  • Trade off is won't be able to drag from desktop or between windows

Features

How

Overview Concept

 draggable can be picked up, moved and dropped over droppable containers.

DndContext

import React from 'react';
import {DndContext} from '@dnd-kit/core';

import {Draggable} from './Draggable';
import {Droppable} from './Droppable';

function App() {
  return (
    <DndContext>
      <Draggable />
      <Droppable />
    </DndContext>
  )
}

In order for your Droppable and Draggable components to interact with each other, you'll need to make sure that the part of your React tree that uses them is nested within  a parent <DndContext> component.

import React from 'react';
import {useDroppable} from '@dnd-kit/core';

function Droppable(props) {
  const {isOver, setNodeRef} = useDroppable({
    id: 'droppable',
  });
  const style = {
    color: isOver ? 'green' : undefined,
  };
  
  
  return (
    <div ref={setNodeRef} style={style}>
      {props.children}
    </div>
  );
}

Let's set up your first Droppable component. When a draggable element is moved over your droppable element, the isOver property will become true.

Change the bg to green when isOver

import React from 'react';
import {useDraggable} from '@dnd-kit/core';

function Draggable(props) {
  const {attributes, listeners, setNodeRef, transform} = useDraggable({
    id: 'draggable',
  });
  const style = transform ? {
    transform: `translate3d(${transform.x}px, ${transform.y}px, 0)`,
  } : undefined;

  
  return (
    <button ref={setNodeRef} style={style} {...listeners} {...attributes}>
      {props.children}
    </button>
  );
}

Next, let's take a look at implementing our first Draggable component. After a draggable item is picked up, the transform property will be populated with the translate coordinates you'll need to move the item on the screen.  

Putting the Pieces Together

Next we need to define what happens when draggable is dropped into droppable.

onDragEnd

  • Fires after a draggable item is dropped.
  • Contains information about the active draggable item
import React from 'react';
import {DndContext} from '@dnd-kit/core';

import {Droppable} from './Droppable';
import {Draggable} from './Draggable';

function App() {
  const [isDropped, setIsDropped] = useState(false);
  const draggableMarkup = (
    <Draggable>Drag me</Draggable>
  );
  
  return (
    <DndContext onDragEnd={handleDragEnd}>
      {!isDropped ? draggableMarkup : null}
      <Droppable>
        {isDropped ? draggableMarkup : 'Drop here'}
      </Droppable>
    </DndContext>
  );
  
  function handleDragEnd(event) {
    if (event.over && event.over.id === 'droppable') {
      setIsDropped(true);
    }
  }
}

onDragEnd

Define a onDragEnd handler to update isDropped state.

 

if isDropped is true, show Draggable item inside the Droppable area.

Demo

import React from 'react';
import {DndContext} from '@dnd-kit/core';

import {Droppable} from './Droppable';
import {Draggable} from './Draggable';

function App() {
  const containers = ['A', 'B', 'C'];
  const [parent, setParent] = useState(null);
  const draggableMarkup = (
    <Draggable id="draggable">Drag me</Draggable>
  );

  return (
    <DndContext onDragEnd={handleDragEnd}>
      {parent === null ? draggableMarkup : null}

      {containers.map((id) => (
        // We updated the Droppable component so it would accept an `id`
        // prop and pass it to `useDroppable`
        <Droppable key={id} id={id}>
          {parent === id ? draggableMarkup : 'Drop here'}
        </Droppable>
      ))}
    </DndContext>
  );

  function handleDragEnd(event) {
    const {over} = event;

    // If the item is dropped over a container, set it as the parent
    // otherwise reset the parent to `null`
    setParent(over ? over.id : null);
  }
};

Multiple Droppables Example

DndContext: Props

interface Props {
  announcements?: Announcements;
  autoScroll?: boolean;
  cancelDrop?: CancelDrop;
  children?: React.ReactNode;
  collisionDetection?: CollisionDetection;
  layoutMeasuring?: Partial<LayoutMeasuring>;
  modifiers?: Modifiers;
  screenReaderInstructions?: ScreenReaderInstructions;
  sensors?: SensorDescriptor<any>[];
  onDragStart?(event: DragStartEvent): void;
  onDragMove?(event: DragMoveEvent): void;
  onDragOver?(event: DragOverEvent): void;
  onDragEnd?(event: DragEndEvent): void;
  onDragCancel?(): void;
}

Presets: Sortable

dnd-kit provides all the building blocks to build a sortable interface from scratch but there's already a preset for that.

 

more presets for common uses cases are coming in the future.

Resources

dnd kit: A lightweight, performant, accessible and extensible drag & drop toolkit for React

By Wan Mohd Hafiz

dnd kit: A lightweight, performant, accessible and extensible drag & drop toolkit for React

  • 508