Drag and drop with dnd-kit
Maya Patel
Jan 2026
1 tab
import { useState } from 'react'
import {
DndContext,
closestCenter,
KeyboardSensor,
PointerSensor,
useSensor,
useSensors,
DragEndEvent,
} from '@dnd-kit/core'
import {
arrayMove,
SortableContext,
sortableKeyboardCoordinates,
verticalListSortingStrategy,
useSortable,
} from '@dnd-kit/sortable'
import { CSS } from '@dnd-kit/utilities'
import { Post } from '@/types'
function SortablePost({ post }: { post: Post }) {
const { attributes, listeners, setNodeRef, transform, transition } = useSortable({
id: post.id,
})
const style = {
transform: CSS.Transform.toString(transform),
transition,
}
return (
<div ref={setNodeRef} style={style} {...attributes} {...listeners} className="bg-white p-4 rounded shadow mb-2 cursor-move">
<h3 className="font-bold">{post.title}</h3>
<p className="text-gray-600 text-sm">{post.excerpt}</p>
</div>
)
}
export function SortablePosts({ initialPosts }: { initialPosts: Post[] }) {
const [posts, setPosts] = useState(initialPosts)
const sensors = useSensors(
useSensor(PointerSensor),
useSensor(KeyboardSensor, {
coordinateGetter: sortableKeyboardCoordinates,
})
)
const handleDragEnd = async (event: DragEndEvent) => {
const { active, over } = event
if (over && active.id !== over.id) {
setPosts((items) => {
const oldIndex = items.findIndex((item) => item.id === active.id)
const newIndex = items.findIndex((item) => item.id === over.id)
const newOrder = arrayMove(items, oldIndex, newIndex)
// Persist to backend
updatePostOrder(newOrder.map((p) => p.id))
return newOrder
})
}
}
return (
<DndContext sensors={sensors} collisionDetection={closestCenter} onDragEnd={handleDragEnd}>
<SortableContext items={posts.map((p) => p.id)} strategy={verticalListSortingStrategy}>
{posts.map((post) => (
<SortablePost key={post.id} post={post} />
))}
</SortableContext>
</DndContext>
)
}
async function updatePostOrder(postIds: string[]) {
// API call to persist order
}
1 file · typescript
Explain with highlit
Drag and drop UIs feel natural for reordering lists or organizing content. The dnd-kit library provides accessible, performant drag and drop with full keyboard support. I use DndContext to wrap draggable areas, useSortable for sortable list items, and SortableContext to manage ordering. The library handles touch events, mouse events, and keyboard navigation automatically. When items are dropped, I update local state optimistically and persist the new order to Rails via API. Animations during drag make interactions feel smooth. The accessibility features mean keyboard-only users can reorder items with arrow keys and space/enter, meeting WCAG standards.