React DnD HTML5 Backend

16.0.1 · active · verified Sun Apr 19

react-dnd-html5-backend provides an essential implementation for drag-and-drop functionality within the React DnD ecosystem, leveraging the native HTML5 Drag and Drop API. This backend handles the intricacies of browser-specific drag and drop events and interactions, abstracting them into React DnD's unified API for consistent use across applications. The current stable version is 16.0.1, and the package actively aligns with the release cadence of the core react-dnd library. Its key differentiator lies in its robust reliance on the browser's built-in HTML5 drag-and-drop capabilities, offering a performant and widely supported solution. Recent major updates, notably in versions 15 and 16, have focused on migrating to ESM-only modules, deprecating the older Decorators API in favor of a Hooks-based approach, and improving compatibility with modern JavaScript environments and Node.js runtimes.

Common errors

Warnings

Install

Imports

Quickstart

This quickstart demonstrates a basic sortable list using React DnD with the HTML5 Backend, showcasing DndProvider, useDrag, and useDrop hooks to enable drag-and-drop reordering of cards.

import { HTML5Backend } from 'react-dnd-html5-backend';
import { DndProvider, useDrag, useDrop } from 'react-dnd';
import React from 'react';
import ReactDOM from 'react-dom';

const ItemTypes = {
  CARD: 'card'
};

interface CardProps {
  id: number;
  text: string;
  moveCard: (id: number, to: number) => void;
  index: number;
}

const Card: React.FC<CardProps> = ({ id, text, moveCard, index }) => {
  const ref = React.useRef<HTMLDivElement>(null);

  const [, drop] = useDrop<CardProps, unknown, unknown>({
    accept: ItemTypes.CARD,
    hover(item, monitor) {
      if (!ref.current) {
        return;
      }
      const dragIndex = item.index;
      const hoverIndex = index;
      if (dragIndex === hoverIndex) {
        return;
      }
      const hoverBoundingRect = ref.current?.getBoundingClientRect();
      const hoverMiddleY = (hoverBoundingRect.bottom - hoverBoundingRect.top) / 2;
      const clientOffset = monitor.getClientOffset();
      const hoverClientY = clientOffset!.y - hoverBoundingRect.top;

      if (dragIndex < hoverIndex && hoverClientY < hoverMiddleY) {
        return;
      }
      if (dragIndex > hoverIndex && hoverClientY > hoverMiddleY) {
        return;
      }
      moveCard(item.id, hoverIndex);
      item.index = hoverIndex;
    }
  });

  const [{ isDragging }, drag] = useDrag({
    type: ItemTypes.CARD,
    item: { id, index, text },
    collect: (monitor) => ({
      isDragging: monitor.isDragging()
    })
  });

  drag(drop(ref));

  return (
    <div
      ref={ref}
      style={{
        border: '1px dashed gray',
        padding: '0.5rem 1rem',
        marginBottom: '.5rem',
        backgroundColor: 'white',
        cursor: 'move',
        opacity: isDragging ? 0.4 : 1
      }}
    >
      {text}
    </div>
  );
};

const Container: React.FC = () => {
  const [cards, setCards] = React.useState([
    { id: 1, text: 'Write a cool JS library' },
    { id: 2, text: 'Make it generic enough' },
    { id: 3, text: 'Write some docs' },
    { id: 4, text: 'Profit' }
  ]);

  const moveCard = React.useCallback((id: number, to: number) => {
    const dragIndex = cards.findIndex(card => card.id === id);
    const dragCard = cards[dragIndex];
    const newCards = [...cards];
    newCards.splice(dragIndex, 1);
    newCards.splice(to, 0, dragCard);
    setCards(newCards);
  }, [cards]);

  return (
    <div>
      {cards.map((card, i) => (
        <Card key={card.id} id={card.id} text={card.text} index={i} moveCard={moveCard} />
      ))}
    </div>
  );
};

ReactDOM.render(
  <DndProvider backend={HTML5Backend}>
    <Container />
  </DndProvider>,
  document.getElementById('root')
);

view raw JSON →