A flexible and lightweight drag-and-drop toolkit for React. Build sortable lists, grids, and Kanban boards with a simple, fully-controlled API and customizable previews. Powered by Atlassian's pragmatic drag-and-drop under the hood.
- ๐ Sortable lists (vertical / horizontal)
- ๐ฏ Controlled: you own the array, update on
onReorder - ๐งฉ Custom render per item (cards, compact, detailedโฆ anything)
- ๐งฒ Drop indicator + optional custom drag preview
- ๐ Full-featured Kanban board with column and card management
- ๐ Cross-column dragging - Move cards between columns seamlessly
- ๐จ Headless architecture - Complete styling control
- โฟ Accessible - Screen reader announcements and keyboard support
- ๐ฑ Touch-friendly - Works on mobile devices
- ๐ฏ TypeScript-first - Full type safety
- ๐งช TypeScript types included
- โก Tiny bundles (~5KB main, ~9KB Kanban)
- ๐จ Framework agnostic styling - Works with Tailwind, MUI, Chakra, etc.
- ๐ Comprehensive documentation
npm i react-dragdrop-kit
# or
yarn add react-dragdrop-kit
# or
pnpm add react-dragdrop-kitimport { useState } from "react";
import { DragDropList } from "react-dragdrop-kit";
function App() {
const [items, setItems] = useState([
{ id: "1", position: 0, title: "Learn React" },
{ id: "2", position: 1, title: "Build awesome app" },
{ id: "3", position: 2, title: "Deploy to production" },
]);
return (
<DragDropList
items={items}
onReorder={(next) => setItems(next.map((it, i) => ({ ...it, position: i })))}
renderItem={(item) => (
<div style={{ padding: 12, border: "1px solid #e5e7eb", borderRadius: 8 }}>
{item.title}
</div>
)}
showDropIndicator
gap={8}
/>
);
}import { useState } from 'react';
import {
KanbanBoard,
applyDragResult,
AnnouncerProvider,
} from 'react-dragdrop-kit/kanban';
function App() {
const [state, setState] = useState({
columns: [
{ id: 'todo', title: 'To Do', cardIds: ['task-1', 'task-2'] },
{ id: 'done', title: 'Done', cardIds: [] },
],
cards: {
'task-1': { id: 'task-1', title: 'Design landing page' },
'task-2': { id: 'task-2', title: 'Implement auth' },
},
});
const handleDragEnd = (result) => {
if (!result.destination) return;
setState(applyDragResult(state, result));
};
return (
<AnnouncerProvider>
<KanbanBoard
state={state}
onDragEnd={handleDragEnd}
renderColumn={(col) => <div style={{ padding: 16 }}>{col.title}</div>}
renderCard={(card) => (
<div style={{ padding: 12, background: '#fff', borderRadius: 8 }}>
{card.title}
</div>
)}
/>
</AnnouncerProvider>
);
}import { DragDropList } from "react-dragdrop-kit";
export default function TailwindExample() {
const [items, setItems] = useState([
{ id: "1", position: 0, name: "Dashboard", icon: "๐" },
{ id: "2", position: 1, name: "Projects", icon: "๐" },
{ id: "3", position: 2, name: "Team", icon: "๐ฅ" },
]);
return (
<DragDropList
items={items}
onReorder={(next) => setItems(next.map((it, i) => ({ ...it, position: i })))}
containerClassName="bg-gray-50 rounded-xl p-6 space-y-2"
itemClassName="bg-white rounded-lg shadow-sm hover:shadow-lg transition-all duration-200 cursor-move"
showDropIndicator
dropIndicatorClassName="bg-blue-500"
renderItem={(item) => (
<div className="flex items-center p-4 space-x-3">
<span className="text-2xl">{item.icon}</span>
<span className="font-medium text-gray-700">{item.name}</span>
</div>
)}
/>
);
}| Prop | Type | Default | Description |
|---|---|---|---|
items |
Array<DraggableItem & T> |
โ | Items to render. Must include { id: string; position: number }. |
onReorder |
(next: T[], updates: OrderUpdate[]) => void |
โ | Called after drop. next is the new array; updates has id + newPosition. |
renderItem |
(item: T) => React.ReactNode |
โ | Custom renderer for each item. |
direction |
"vertical" | "horizontal" |
"vertical" |
Drag axis + layout. |
gap |
number |
0 |
Gap (px) between items. |
disabled |
boolean |
false |
Disable dragging. |
showDropIndicator |
boolean |
false |
Show a drop indicator while dragging. |
dropIndicatorPosition |
"top" | "bottom" |
"bottom" |
Position of drop indicator relative to target item. |
dropIndicatorClassName |
string |
โ | CSS class applied to the drop indicator element. |
dragPreviewStyle |
React.CSSProperties |
โ | Inline styles for custom drag preview. |
containerClassName |
string |
โ | Class applied to the container. |
itemClassName |
string |
โ | Class applied to each item wrapper. |
See the Kanban Documentation for complete API reference, including:
KanbanBoard- High-level componentKanbanColumnView- Headless column componentKanbanCardView- Headless card componentAnnouncerProvider- Accessibility provider- Helper utilities and types
- โ Drag cards within and between columns
- โ Reorder columns by dragging headers
- โ Empty column support - Drop into columns with no cards
- โ Cancel drag - Drop outside board to cancel
- โ Normalized state - Efficient data structure
- โฟ Screen reader support with live announcements
- ๐น Keyboard navigation (infrastructure ready)
- ๐ท๏ธ Proper ARIA attributes
- ๐ข Context-aware messages
- ๐ Full TypeScript support
- ๐จ Headless architecture - Style with any framework
- ๐ง Helper utilities -
applyDragResult, reorder functions - ๐ Migration guide from react-beautiful-dnd
The Kanban board is completely headless, giving you full control:
- Custom card designs
- Custom column headers
- Theme support
- Animation styles
- Responsive layouts
This repo includes comprehensive examples:
๐ Explore the examples/ folder for the complete code.
๐ฎ Live Demo: Check out our interactive demo app with full Kanban showcase!
import type { DraggableItem, OrderUpdate, KanbanBoardState, DropResult } from 'react-dragdrop-kit';
import type { KanbanCard, KanbanColumn } from 'react-dragdrop-kit/kanban';
// Extend with custom fields
interface TodoItem extends DraggableItem {
title: string;
completed: boolean;
}
interface ProjectCard extends KanbanCard {
priority: 'low' | 'medium' | 'high';
assignee: string;
tags: string[];
}In dev, React Strict Mode double-mounts to surface side effects. If you see duplicate onReorder calls in development, ensure your event listeners clean up correctly and keep callback identities stable with useCallback. Production builds call once.
| Module | Size (Minified) |
|---|---|
react-dragdrop-kit (Main) |
~5KB |
react-dragdrop-kit/kanban |
~9KB |
Tree-shakeable exports mean you only pay for what you use!
See our comprehensive Kanban migration guide for step-by-step instructions on migrating from react-beautiful-dnd.
Key differences:
- Normalized state structure
- No auto-generated IDs
- Render props instead of children
- Better TypeScript support
Contributions are welcome! Please feel free to submit a Pull Request.
MIT ยฉ Yourstruggle11
Built with:
@atlaskit/pragmatic-drag-and-drop- Performance-focused drag and drop- Inspired by
react-beautiful-dndAPI design - Community feedback and contributions
- Kanban Board Guide
- Known Issues & Limitations
- CHANGELOG
- Examples
- Demo Application โ open โKnown Issuesโ from the sidebar
- ๐ Report Issues
- ๐ก Request Features
- โญ Star on GitHub