Type to generate custom UI components with AI

Type to generate UI components from text

OR

Browse thousands of MUI, Tailwind, React components that are fully customizable and responsive.

Explore Components

Understanding React Beautiful DND for User-Friendly Apps

Drag and drop functionality is everywhere in today’s web applications, providing users with a natural way to interact with elements on a webpage. In this article, we’ll delve into the basics of how to create React beautiful DND interactions, explaining why they’re crucial for crafting user-friendly interfaces.

At its core, drag-and-drop functionality allows users to click and drag elements on a webpage and drop them onto specific areas. It’s a common way for users to interact with different applications, like file managers or task organizers.

Basic Principles of a Drag and Drop Feature

The drag-and-drop process typically involves three main phases:

  1. Drag Start: Initiates the drag operation by clicking and holding onto a draggable element.

  2. Dragging: Moving the element to a desired location while still holding down the mouse button.

  3. Drop: Releasing the mouse button to “drop” the element into a designated drop zone.

Users anticipate smooth, responsive, intuitive, and beautiful DND interactions. A seamlessly executed drag-and-drop feature boosts user engagement and satisfaction with the application.

Importance of Intuitive User Interfaces

Creating intuitive user interfaces is essential for delivering a positive user experience. The DND functionality streamlines tasks, enabling users to work more efficiently without navigating complex menus or clicking multiple times.

Enhancing User Engagement and Satisfactions

By providing a visually intuitive way to manipulate content, DND interfaces encourage users to interact more actively with the application. This increased engagement can lead to higher user satisfaction and retention rates.

Streamlining Complex Actions Through DND

Complex actions, such as rearranging items in a list or uploading files, can be simplified with drag-and-drop functionality. This streamlines the user workflow and reduces cognitive load, resulting in a more enjoyable user experience.

Brief Comparison of Various DND Functionalities

Several libraries are available for implementing DND functionality in web applications. Let’s briefly compare some popular packages amongst the vast majority of options we have available:

  • React Beautiful DND: A powerful and flexible library specifically designed for DND interactions in React applications.

  • React-dnd: This is another popular choice for DND in React, offering a more customizable approach with support for complex interactions.

  • HTML5 Drag-and-Drop API: The native HTML5 DND API provides basic drag-and-drop functionality without the need for external libraries. However, it lacks some advanced features and may be more challenging to implement for complex use cases.

In the next sections, we will delve into React Beautiful DND, exploring its features, advantages, and how to get started with implementing drag-and-drop functionality in your React projects. Let’s dive in!

What is React Beautiful DND?

React Beautiful DND stands out as a powerful tool for streamlining and building accessible drag-and-drop functionalities in React applications. In this section, we’ll explore React Beautiful DND, covering its key features and benefits.

React Beautiful DND, developed by Atlassian, is built on top of the native HTML5 Drag and Drop API and offers a more declarative and intuitive way to handle DND interactions in React applications.

It provides a powerful API and utilities that make it easy to create complex DND minimal boilerplate code. Although the wonderful maintainers are no longer actively monitoring issues that are being logged and also not approving pull requests on GitHub till further notice, we can still leverage its APIs to build something wonderful.

Key Features and Advantages

We’ve learned briefly about what React Beautiful DND is, now let’s look at its key features and why we should consider using it.

Flexible and Declarative API

React Beautiful DND stands out for its flexible and clear API, which empowers developers to define DND behavior using straightforward JSX syntax. By handling the intricate aspects of DND interactions behind the scenes, React Beautiful DND lets developers concentrate on creating user-friendly interfaces without getting tangled in technical complexities.

import { DragDropContext, Droppable, Draggable } from 'react-beautiful-dnd';

function App() {
  return (
    <DragDropContext>
      <Droppable droppableId="droppable">
        {(provided) => (
          <div ref={provided.innerRef} {...provided.droppableProps}>
            {items.map((item, index) => (
              <Draggable key={item.id} draggableId={item.id} index={index}>
                {(provided) => (
                  <div
                    ref={provided.innerRef}
                    {...provided.draggableProps}
                    {...provided.dragHandleProps}
                  >
                    {item.content}
                  </div>
                )}
              </Draggable>
            ))}
          </div>
        )}
      </Droppable>
    </DragDropContext>
  );
}

This is just an example of a typical implementation of the React Beautiful DND package, we will go over how to properly set up our codebase so we can take advantage of the methods and components it has available to make complex functionalities.

Robust Support for Touch Devices and Screen Readers

React Beautiful DND is designed to work smoothly on different devices and for people with various accessibility needs. It comes with built-in support for touchscreens, so users can easily DND items using touch. Plus, it’s accessible to everyone, including those with disabilities, thanks to features like proper labelling for screen readers and support for navigating with keyboards.

Getting Started with React Beautiful DND

In this part, we’ll walk through the process of getting started with React Beautiful DND, from installing it to using it in simple examples. By the end, you’ll have a basic knowledge of how to integrate this package into your React projects and start using them effectively.

Installation and Setup

To begin using React Beautiful DND in your project, you must first install the library via npm or yarn. Open your terminal and navigate to your project directory, then run one of the following commands:

npm install react-beautiful-dnd

or

yarn install react-beautiful-dnd

Once the installation is complete, you can import the necessary components from the react-beautiful-dnd package and start using them in your React components.

Core Concepts

Integrating React Beautiful DND into your React project is straightforward. The core characteristics typically include these three main components provided by the library: `DragDropContext`, `Droppable`, and `Draggable`.

PS: Engineers waste time building and styling components when working on a project, writing repetitive markup adds time to the project and is a mundane, boring task for engineers. PureCode.ai uses AI to generate a large selection of custom, styled UI components for different projects and component types.

DradDropContext

The `DragDropContext` component is a higher-order component that wraps your entire application and provides the context for DND interactions. You should place it at the root level of your React application.

import { DragDropContext } from 'react-beautiful-dnd';

function App() {
  return (
    <DragDropContext>
      {/* Your components go here */}
    </DragDropContext>
  );
}

export default App

We start by importing`DragDropContext` from the drag and drop library. This component is very essential for creating DND functionality in React.

Droppable

`Droppable` defines an area where draggable elements can be dropped. It acts as a container for the items that will be draggable.

Let’s take a look at the block of code below

import { DragDropContext, Droppable } from 'react-beautiful-dnd';

function App() {
  return (
    <DragDropContext>
      <Droppable droppableId="droppable">
        {(provided) => (
          <div
            ref={provided.innerRef}
            {...provided.droppableProps}
          >
            {/* Draggable items go here */}
          </div>
        )}
      </Droppable>
    </DragDropContext>
  );
}

export default App

To define the droppable area we initialize `Droppable` and add a unique identifier `droppableId` with the value of `droppable` as a string. This helps React Beautiful DND differentiate between different droppable areas.

Next, `Droppable` takes a function as a child. This function receives a parameter (`provided`) containing properties and functions by `Droppable` for rendering the droppable area.

In the render prop function, we’re creating a `<div>` element to serve as the drop target for draggable items. To handle DOM interactions effectively, we need to reference this `<div>`. We achieve this by utilizing the `ref` attribute.

The reference to this `<div>` is obtained from the `innerRef` property available within the `provided` object passed by `Droppable`, accessed as `provided.innerRef`. This reference is then passed into the `ref` attribute of the `<div>`, allowing React Beautiful DND to manage the interaction with the DOM.

Additionally, we spread any additional props provided by `Droppable` to ensure correct functionality (`…provided.droppableProps`).

Next, we move on to the `Draggable` component.

Draggable

The `Draggable` component represents an item that can be dragged within a `Droppable` area.

import { Draggable, DragDropContext, Droppable } from 'react-beautiful-dnd';

function App() {
  return (
    <DragDropContext>
      <Droppable droppableId="droppable">
        {(provided) => (
          <div
            ref={provided.innerRef}
            {...provided.droppableProps}
          >
            <Draggable draggableId={item.id} index={index}>
              {(provided, snapshot) => (
                <div
                  ref={provided.innerRef}
                  {...provided.draggableProps}
                  {...provided.dragHandleProps}
                >
                  {item.content}
                </div>
              )}
            </Draggable>
          </div>
        )}
      </Droppable>
    </DragDropContext>
  );
}

export default App;

Let’s go over the code for the `Draggable` component above.

The `Draggable` component requires two props: `draggableId` and `index`. The `draggableId` uniquely identifies the draggable item and `index` specifies the position of the item in the list of drag items.

Just like`Droppable` the `Draggable` component accepts a function as a child known as the render prop. The function receives two parameters: `provided`, which contains properties and functions provided by the `Draggable` component, and `snapshot`, which provides information about the current drag state of the drag items.

The `<div>` is the JSX element representing the draggable item itself. It’s wrapped within the render prop function provided by `Draggable`.

We need to add a couple of properties which is returned from the `Draggable` component. Firstly, we attach the `provided.innerRef` to the ref attribute, we also go on to spread the props `draggableProps` from the `Draggable` component like so `{…provided.draggableProps}`. These props include essential attributes for drag behavior, such as `data-draggable-id` and `data-drag-handle-id`.

Finally, we spread the `dragHandleProps` that’s being returned from the `Draggable` component specifically for the drag handle onto the `<div>` element like so `{…provided.dragHandleProps}`. Drag handles allow users to drag the element by a specific part of it, rather than the whole element.

`{item.content}` is the actual content of the draggable item. The `item` object contains properties such as the `id` and `content`, with content representing text or HTML to be displayed within the dragging item.

Now, that we have gone over the core characteristics of `react-beautiful-dnd` we can take all these and apply them to an example.

Basic Usage Examples

Now to put into effect what we have learnt in the earlier sections will implement the DND through the following example. First, we will start with defining the list.

Let us define our list and map through it

import React from "react";

const characters = [
  {
    id: "jeff",
    name: "Jeffery",
  },
  {
    id: "john",
    name: "John",
  },
  {
    id: "toby",
    name: "Toby",
  },
  {
    id: "matt",
    name: "Matt",
  },
  {
    id: "faith",
    name: "Faith",
  },
  {
    id: "david",
    name: "David",
  },
];

function App() {
  return (
    <div className="items__wrapper">
      <ul className="items__list" >
        {characters.map(({ id, name }) => {
          return (
            <li key={id} className="item" >
              {name}
            </li>         
          );
        })}       
      </ul>
    </div>
  );
}

export default App;

We crafted a list and iterated through its elements with the map function to render them on the DOM. The result is shown in the image below.

mapping through a list (characters) to display on the DOM

Adding the CSS Styles

Now we add some styling to make it look a little bit presentable.

/* ./App.css */

.items__wrapper {
  height: 100vh;
  display: flex;
  justify-content: center;
  align-items: center;
}

.items__list {
  display: flex;
  flex-direction: column;
  gap: 20px;
  justify-content: center;
  align-items: center;
  border: 1px solid black;
  padding: 20px;
  border-radius: 4px;
}

.item {
  width: 300px;
  height: 60px;
  display: flex;
  justify-content: center;
  align-items: center;
  border: 1px solid black;
  border-radius: 4px;
  background-color: #fff;
}

We have this output below.

list with some styling added

Next, we import the `DragDropContext` from `react-beautiful-dnd` and we will use it to wrap our entire application just like the way we did it earlier.

import { DragDropContext } from "react-beautiful-dnd";

function App() {
  return (
    <DragDropContext>
      <div className="items__wrapper">
        <ul className="items__list" >
          {characters.map(({ id, name }) => {
            return (
              <li key={id} className="item" >
                {name}
              </li>         
            );
          })}       
        </ul>
      </div>
    </DragDropContext>
  );
}

export default App;

Adding the Droppable Component

We will go on to add `Droppable` and set the `droppableId` to characters to uniquely identify this droppable area.

The next thing is to add the render prop function that is provided by `Droppable`. It receives a parameter `provided` containing properties and functions provided by `Droppable` for rendering the droppable area. We destructure the provided object to get the `droppableProps` and spread it as well as the `innerRef`, but we add that to the `ref` attribute.

import { DragDropContext, Droppable } from "react-beautiful-dnd";

function App() {
  return (
    <DragDropContext>
      <Droppable droppableId="characters" >
      <div className="items__wrapper">
        {(provided) => (
          <ul 
            {...provided.droppableProps}
            ref={provided.innerRef}
            className="items__list" 
          >
            {characters.map(({ id, name }) => {
              return (
                <li key={id} className="item" >
                  {name}
                </li>         
              );
            })}       
          </ul>
        </div>
      </Droppable>
    </DragDropContext>
  );
}

export default App;

Adding the Draggable Component

Furthermore, we add the `Draggable` component to the individual items on the list and add the additional props that need to be added. This component represents a draggable item within the list.

To make the `Draggable` component work properly we need to add the `draggableId` and the `index` and that can come from the `id` and `index` from our character list.

import { DragDropContext, Droppable } from "react-beautiful-dnd";

function App() {
  return (
    <DragDropContext>
      <Droppable droppableId="characters" >
      <div className="items__wrapper">
        {(provided) => (
          <ul 
            {...provided.droppableProps}
            ref={provided.innerRef}
            className="items__list" 
          >
            {characters.map(({ id, name }, index) => {
              return (
                <Draggable
                  key={id}
                  draggableId={id}
                  index={index}
                >
                  <li className="item" >
                    {name}
                  </li>
                </Draggable>         
              );
            })}       
          </ul>
        </div>
      </Droppable>
    </DragDropContext>
  );
}

export default App;

After, implementing the `Draggable` component, the next thing is to define the render prop function. The function receives `provided` and `snapshot` parameters containing the properties and functions by `Draggable` for managing the `draggableItem`.

For the list item, (`<li>`) represents the draggable character. It spreads the `draggableProps` and `dragHandleProps` provided by `Draggable` onto the `<li>` element, attaches a reference (`innerRef`) for managing the DOM node, and applies dynamic styling based on the drag state (`snapshot.isDragging`). We also added the key prop to make React keep track of the elements in the list.

import { DragDropContext, Droppable } from "react-beautiful-dnd";

function App() {
  return (
    <DragDropContext>
      <Droppable droppableId="characters" >
      <div className="items__wrapper">
        {(provided) => (
          <ul 
            {...provided.droppableProps}
            ref={provided.innerRef}
            className="items__list" 
          >
            {characters.map(({ id, name }, index) => {
              return (
                <Draggable
                  key={id}
                  draggableId={id}
                  index={index}
                >
                  {(provided, snapshot) => (
                    <li 
                      {...provided.draggableProps}
                      {...provided.dragHandleProps}
                      ref={provided.innerRef}
                      className="item"
                      style={{
                        ...provided.draggableProps.style,
                        background: snapshot.isDragging ? "lime" : "white"
                      }}
                    >
                      {name}
                    </li>
                  )}
                </Draggable>         
              );
            })}       
          </ul>
        </div>
      </Droppable>
    </DragDropContext>
  );
}

export default App;

Adding the onDragEnd Function

We still cannot drag and drop elements on the droppable area because we need to add a function to the `DragDropContext` to track and reorder the elements on the list. We also need a local state where we can manipulate the order of the list.

<DragDropContext onDragEnd={handleDrag}>

Now to properly define the `handleDrag` we need to first define the local state.

const [names, updateNames] = useState(characters);

`const [names, updateNames] = useState(characters)` initializes the state variable `names` using the `useState` hook. It sets the initial state to the `characters` array provided as an argument.

We also need to update the variable name used in mapping our list from `characters`

{characters.map(({ id, name }, index) => {

to `names`, which represents the local state that we just created.

{names.map(({ id, name }, index) => {

Let’s take a closer look at the code block below;

const handleDrag = (result) => {
 console.log(result)
}; 

When we drag an item to another position, although we have not yet written the logic for the reorder, the result object gives us access to the following properties which we can see in the image below.

the result object

From the image we have above, what we need the most is the `destination` property and the `source` property so we can properly sort the list.

The Reordering Logic

const handleDrag = (result) => {
  const { source, destination } = result;

  const updatedNames = Array.from(names);
  const [reOrderedItem] = updatedNames.splice(source.index, 1);
  updatedNames.splice(destination.index, 0, reOrderedItem);

  updateNames(updatedNames);
}; 

`const { source, destination } = result` uses object destructuring to extract the `source` and `destination` properties from `result`. These properties represent the starting and ending positions of a drag operation.

`const updatedNames = Array.from(names)` creates a copy of the `names` array using `Array.from()` method. This is done to avoid directly mutating the original state.

`const [reOrderedItem] = updatedNames.splice(source.index, 1)` removes the item being dragged (`reOrderedItem`) from its original position (`source.index`) in the `updatedNames` array using the `splice()` method.

The `splice()` method returns an array containing the removed items, and using array destructuring, we assign the removed item to the `reOrderedItem` variable.

`updatedNames.splice(destination.index, 0, reOrderedItem)` inserts the `reOrderedItem` at the new position specified by `destination.index` in the `updatedNames` array using the `splice()` method.

The `0` as the second argument indicates that no items should be removed before inserting the `reOrderedItem`.

`updateNames(updatedNames)` calls the `updateNames` function, passing the `updatedNames` array as an argument.

It updates the `names` state with the modified array, causing React to re-render the component with the updated list of names.

Tips and Best Practices for Performance Optimization

When working with React Beautiful DND, it’s essential to follow best practices to ensure optimal performance and reliability of your DND components. In this section, we’ll discuss key tips and best practices, including performance optimization strategies and testing methodologies.

Optimizing the performance of DND components is crucial, especially in large applications where performance bottlenecks can significantly impact user experience. Here are some strategies for optimizing performance

Identifying and Mitigating Performance Bottlenecks

Profiling: Use performance profiling tools to identify areas of your application that are causing performance issues. Focus on optimizing code that contributes to drag-and-drop interactions.

Memoization: Utilize memoization techniques to cache expensive computations and avoid unnecessary re-renders.

Implementing Lazy Loading and Deferred Rendering

Lazy Loading: Implement lazy loading techniques to load drag-and-drop components dynamically, only when needed. This can reduce the initial load time of your application.

Deferred Rendering: Use deferred rendering to delay rendering non-essential drag-and-drop elements until they’re in the viewport. This can improve the perceived performance of your application.

Example of Lazy Loading with React Suspense

import React, { Suspense } from 'react';
import { DragDropContext, Droppable, Draggable } from 'react-beautiful-dnd';

const LazyDraggableComponent = React.lazy(() => import('./DraggableComponent'));

function App() {
  return (
    <DragDropContext>
      <Suspense fallback={<div>Loading...</div>}>
        <Droppable droppableId="droppable">
          {/* Render Droppable component */}
        </Droppable>
      </Suspense>
    </DragDropContext>
  );
}

Debouncing and Throttling Drag-and-Drop Events

Debouncing and throttling are techniques used to manage the frequency of drag-and-drop events, preventing performance degradation and ensuring optimal responsiveness.

Managing Event Frequency

Debouncing: Debouncing delays the execution of a function until after a certain amount of time has passed since the last invocation. This can be useful for handling drag-and-drop events that occur frequently but don’t require immediate action.

Throttling: Throttling limits the rate at which a function can be executed. It ensures that drag-and-drop events are processed at a controlled pace, preventing the browser from becoming overwhelmed with too many updates.

import { debounce } from 'lodash';

const handleDragEnd = debounce((result) => {
  // Handle drag end logic here
}, 300); // Debounce for 300 milliseconds

<DragDropContext onDragEnd={handleDragEnd}>
  {/* Render DragDropContext */}
</DragDropContext>

Recap of Key Points Covered in the Article

In this article, we’ve covered essential concepts and features of React Beautiful DND, a powerful library for implementing drag-and-drop functionality in React applications. Let’s recap the key points we’ve discussed and encourage you to explore and implement React Beautiful DND in your projects.

Throughout the article, we’ve explored the following key concepts and features of React Beautiful DND.

  • Overview: We introduced drag-and-drop functionality in web development and highlighted the importance of intuitive user interfaces. We also compared various drag-and-drop libraries and focused on React Beautiful DND.

  • Introduction to React Beautiful DND: We provided an overview of the library, and discussed its key features, advantages, and adoption within the frontend development community.

  • Getting Started: We walked through the installation process and basic usage examples of React Beautiful DND, demonstrating how to integrate it into React projects.

  • Core Concepts: We delved into the core concepts of React Beautiful DND, including Droppable and Draggable components, and understanding the relationship between containers and items.

  • Tips and Best Practices: We provided tips and best practices for optimizing performance, and troubleshooting common issues when working with React Beautiful DND.

  • Real-world Applications: We showcased real-world examples of React Beautiful DND in action and discussed its impact on user experience and development efficiency.

  • Community and Resources: We encouraged engagement with the React Beautiful DND community and highlighted useful resources and documentation for further learning.

Final Thought on React Beautiful DND

By incorporating React Beautiful DND into your frontend projects, you can:

  • Enhance user experience: Create intuitive and interactive interfaces that allow users to manipulate content effortlessly.

  • Improve development efficiency: Streamline complex actions and workflows with drag-and-drop functionality, reducing development time and effort.

  • Stay up-to-date: Join an active community of developers and leverage ongoing updates and improvements to the library.

As you continue your journey in front-end development, I encourage you to explore and implement React Beautiful DND in your projects. Whether you’re building a task management application, a Kanban board, or an interactive dashboard, drag-and-drop functionality can significantly enhance the usability and effectiveness of your application.

PureCode.ai can cater to your code development process. It will save you valuable time and effort on a project by providing customized, and ready-to-use components which will allow you to prioritize more important and thought-intensive tasks to speed up the development of your user interface.

Shadrach Abba

Shadrach Abba