Implementing Drag and Drop with dnd-kit
in a Next.js Project
This guide will take you through the process of implementing a sortable list using dnd-kit
in a Next.js project. We'll start by creating a list of users, then build the necessary components, and finally implement the drag and drop functionality.
Prerequisites
Make sure you have Node.js and npm installed. Also, have a basic understanding of React and Next.js.
Step 1: Setting Up the Next.js Project
First, create a new Next.js project if you don't already have one:
npx create-next-app@latest dnd-kit-demo
cd dnd-kit-demo
Install the required packages
npm install @dnd-kit/core @dnd-kit/sortable @dnd-kit/utilities
Step 2: Creating the List of Users
- Create a file named data.ts in the data folder (create the folder if it doesn't exist):
- Note the List Must have the id property, its necessary for the dnd
// data/users.ts
export interface User {
id: number;
name: string;
initials: string;
}
export const users: User[] = [
{ id: 1, name: "Alice Johnson", initials: "AJ" },
{ id: 2, name: "Bob Smith", initials: "BS" },
{ id: 3, name: "Charlie Brown", initials: "CB" },
{ id: 4, name: "David Wilson", initials: "DW" },
{ id: 5, name: "Eva Davis", initials: "ED" },
{ id: 6, name: "Frank Miller", initials: "FM" },
{ id: 7, name: "Grace Lee", initials: "GL" },
{ id: 8, name: "Hannah White", initials: "HW" },
{ id: 9, name: "Ian Green", initials: "IG" },
{ id: 10, name: "Jack Black", initials: "JB" },
];
Step 3: Creating the Components
3.1 Home Page Component
Create a Home component that will render the UserList component.
// app/page.tsx
import UserList from "@/components/UserList";
import React from "react";
export default function Home() {
return (
<div>
<UserList />
</div>
);
}
3.2 User List Component
Create the UserList component to render the sortable list of users.
// components/UserList.tsx
"use client";
import { User, users } from "@/data/users";
import {
DndContext,
DragEndEvent,
KeyboardSensor,
PointerSensor,
TouchSensor,
closestCenter,
useSensor,
useSensors,
} from "@dnd-kit/core";
import {
SortableContext,
arrayMove,
sortableKeyboardCoordinates,
verticalListSortingStrategy,
} from "@dnd-kit/sortable";
import React, { useState } from "react";
import { SortableUser } from "./SortableUser";
export default function UserList() {
const [usersList, setUsersList] = useState(users);
function onDragEnd(event: DragEndEvent) {
const { active, over } = event;
if (active.id === over?.id) {
return;
}
setUsersList((users) => {
const oldIndex = users.findIndex((user) => user.id === active.id);
const newIndex = users.findIndex((user) => user.id === over?.id);
return arrayMove(users, oldIndex, newIndex);
});
}
const sensors = useSensors(
useSensor(PointerSensor),
useSensor(TouchSensor),
useSensor(KeyboardSensor, {
coordinateGetter: sortableKeyboardCoordinates,
})
);
return (
<div className="max-w-md mx-auto mt-8">
<h2 className="text-2xl font-bold mb-4">User List</h2>
<ul className="bg-white shadow-md rounded-lg">
<DndContext
sensors={sensors}
collisionDetection={closestCenter}
onDragEnd={onDragEnd}
>
<SortableContext
items={usersList}
strategy={verticalListSortingStrategy}
>
{usersList.map((user: User) => (
<SortableUser key={user.id} user={user} />
))}
</SortableContext>
</DndContext>
</ul>
</div>
);
}
3.3 Sortable User Component
Create the SortableUser component to handle each user item in the list.
// components/SortableUser.tsx
import { User } from "@/data/users";
import { useSortable } from "@dnd-kit/sortable";
import { CSS } from "@dnd-kit/utilities";
export function SortableUser({ user }: { user: User }) {
const { attributes, listeners, setNodeRef, transform, transition } =
useSortable({ id: user.id });
const style = {
transition,
transform: CSS.Transform.toString(transform),
};
return (
<li
ref={setNodeRef}
{...attributes}
{...listeners}
style={style}
className="flex items-center border-b border-gray-200 py-2 px-4 touch-action-none"
>
<div className="flex-shrink-0 w-10 h-10 rounded-full bg-blue-500 text-white flex items-center justify-center">
{user.initials}
</div>
<div className="ml-4 text-gray-700">{user.name}</div>
</li>
);
}
3.4 Add CSS Custom Class to Sortable item
/* styles/globals.css */
@tailwind base;
@tailwind components;
@tailwind utilities;
.touch-action-none {
touch-action: none;
}
Explanation
DndContext: The DndContext component from dnd-kit provides the context for drag and drop functionality. It handles events and sensors. SortableContext: The SortableContext component wraps the list of items that should be sortable. It uses a strategy to define how the items should be sorted. useSortable: The useSortable hook provides the necessary props and refs to make an item sortable. It returns attributes, listeners, and styling properties. arrayMove: The arrayMove utility from dnd-kit helps in reordering the array when an item is dragged and dropped.
- setNoderef : This option specifies which component should be moved when dragging occurs.
- setActivatorNodeRef : This option indicates which element should be used as a reference to detect if the user is initiating a drag action.
- listeners : This option specifies which element should be able to listen to events such as clicks and drags.
- transform : This option is used to set up the necessary styles when an element is being moved due to the drag action.
- transition : This option is used to set up any animations that occur while the element is being moved.