React DnD HTML5 Backend
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
-
ReferenceError: require is not defined
cause Attempting to use CommonJS 'require()' to import the package in an ESM context (Node.js module with `"type": "module"` or modern bundler config).fixChange `const HTML5Backend = require('react-dnd-html5-backend');` to `import { HTML5Backend } from 'react-dnd-html5-backend';`. -
TypeError: (0 , react_dnd__WEBPACK_IMPORTED_MODULE_1__.DndProvider) is not a function
cause Incorrect import or configuration of the DndProvider from 'react-dnd', or the 'backend' prop is missing/invalid.fixEnsure `DndProvider` is correctly imported from 'react-dnd' and passed a valid backend, e.g., `<DndProvider backend={HTML5Backend}>...</DndProvider>`. -
TypeError: 'useDrag' cannot be called inside a class component.
cause Trying to use React Hooks (like `useDrag` or `useDrop`) inside a class component after the Decorators API was removed.fixConvert your class component to a functional component and use the `useDrag` and `useDrop` hooks. Alternatively, if you need class components, use an older `react-dnd` version that supports decorators (pre-v15.0.0). -
Module not found: Can't resolve 'react-dnd-html5-backend'
cause The package is not installed, or there's a typo in the import path.fixRun `npm install react-dnd-html5-backend react-dnd` or `yarn add react-dnd-html5-backend react-dnd` and double-check the import statement for correct spelling.
Warnings
- breaking The package transitioned to ESM-only modules starting with v16.0.0. This means CommonJS 'require()' statements will no longer work, requiring projects to adopt ES Modules for imports or use a bundler that handles ESM correctly.
- breaking The Decorators API was completely removed in v15.0.0 and replaced by the Hooks API. Existing components using decorators (e.g., @DragSource, @DropTarget) must be refactored to use `useDrag` and `useDrop` hooks.
- gotcha Attempting to specify a `begin` method within the `useDrag::spec` configuration will throw a developer exception. This method is intentionally disallowed in the Hooks API.
- gotcha Earlier versions had issues with drag-and-drop operations within iframes or child windows. While a fix was introduced in v14.0.3, ensure you are on a recent version if encountering such problems.
- gotcha v15.0.0 was initially published as ESM-only, but quickly reverted in v15.0.1 due to issues, temporarily restoring CommonJS/ESM format. The permanent transition to ESM-only occurred in v16.0.0. This history can cause confusion if relying on specific minor versions.
Install
-
npm install react-dnd-html5-backend -
yarn add react-dnd-html5-backend -
pnpm add react-dnd-html5-backend
Imports
- HTML5Backend
const HTML5Backend = require('react-dnd-html5-backend')import { HTML5Backend } from 'react-dnd-html5-backend' - DndProvider
import { DndProvider } from 'react-dnd' - BackendFactory
import type { BackendFactory } from 'react-dnd'
Quickstart
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')
);