🪟 Windows TippsAndroid 17: Neue Version ist hier – Das ist alles neu(16.09.2026 um 11:40 Uhr)
🕵️ Hacking12 Best CASB Solutions Compared (2026): Features & Pricing(16.09.2026 um 09:31 Uhr)
🕵️ Hacking12 Best CIEM Tools Compared (2026): Features & Pricing(16.09.2026 um 09:37 Uhr)
🪟 Windows TippsAndroid 17: Neue Version ist hier – Das ist alles neu(16.09.2026 um 11:40 Uhr)
🕵️ Hacking12 Best CASB Solutions Compared (2026): Features & Pricing(16.09.2026 um 09:31 Uhr)
🕵️ Hacking12 Best CIEM Tools Compared (2026): Features & Pricing(16.09.2026 um 09:37 Uhr)

🔧 Programmierung 🕛 vor 2 Jahren 22 Min Lesezeit
0

Implement the Pragmatic drag and drop library

↗ Quelle (dev.to)
🗣️ Stimme:
📑 Inhaltsübersicht

Written by is a performance-focused library that leverages the native HTML Drag and Drop API to create seamless drag-and-drop experiences across any tech stack. With its robust set of functionalities, it offers developers the flexibility to craft fast and beautiful drag-and-drop experiences for their web applications.



Before diving into implementation details, let's explore the key features and advantages that make Pragmatic drag and drop a good choice for developers.






Key features and advantages



Here are some of the key features and advantages of the Pragmatic drag and drop library:




  • It's small in size compared to other libraries in the market — ~4.7kB core package

  • It's compatible with any front-end framework

  • It supports dragging various types of entities, such as elements, text, images, and external files. Unlike , which don't handle file drops, this library covers all drag-and-drop use cases. This means you only need one drag-and-drop library for different purposes in your project

  • It supports lazy loading, allowing developers to delay loading the core and optional packages to improve page load speeds further

  • It allows appearance customization of draggable elements and drag previews

  • Last but not least, it enables dragging elements across different browser windows because internally it uses browser native .






    Build a Kanban board with Pragmatic drag and drop



    In this section, we'll explore the core concepts of the library and understand how its components work together by building a Kanban board. Let's get started!






    Setting up the React project



    To get started quickly, I have created a package along with the library by running the following:




    CODE
    npm i @atlaskit/pragmatic-drag-and-drop @atlaskit/pragmatic-drag-and-drop-hitbox tiny-invariant






    This installs the below:




    • @atlaskit/pragmatic-drag-and-drop: The core Pragmatic drag and drop library

    • @atlaskit/pragmatic-drag-and-drop-hitbox: An optional package that allows attaching interaction information to a drop target

    • tiny-invariant: A lightweight library that helps identify potential errors in your code during development



    With these steps, you have successfully set up your project and installed the necessary packages.



    Now, start the application by running:




    CODE
    npm start






    You can access the application by navigating to



    At this point, you'll observe that none of the cards are draggable. In the next section, we'll learn how to make them draggable.






    Making the cards draggable



    To make an element draggable, we can use the



    In the next section, we'll take this a step further by adding a fading effect to the draggable cards.






    Adding a fading effect to draggable cards



    To add a fading effect while dragging, we need to change the opacity of the Card element when the drag starts and reapply the original style when the drag ends. We'll use the draggable function's event handlers for this purpose.



    Let’s start by creating an isDragging state variable to track the dragging state. Then, update the draggable call within the useEffect hook to add onDragStart and onDrop event handlers. Finally, apply the dragging class to the card div based on the value of isDragging, like this:




    CODE
    import { useEffect, useRef, useState } from "react"; // import useState
    // rest of the imports

    const Card = ({ children, ...card }) => {
    const cardRef = useRef(null);
    const [isDragging, setIsDragging] = useState(false); // create a state for dragging

    useEffect(() => {
    const cardEl = cardRef.current;
    invariant(cardEl);

    return draggable({
    element: cardEl,
    getInitialData: () => ({ type: "card", cardId: card.id }),
    onDragStart: () => setIsDragging(true), // set isDragging to true when dragging starts
    onDrop: () => setIsDragging(false), // set isDragging to false when dragging ends
    });
    }, []);
    return (
    // Add dragging class when isDragging is true
    <div className={`card ${isDragging ? "dragging" : ""}`} ref={cardRef}>
    {children}
    </div>
    );
    };






    When you start dragging a card, the onDragStart event triggers. This event sets a state variable called isDragging to true. This change in state does two things:




    • Adds a dragging class to the card

    • Adjusts the card's opacity to create a visual dragging effect



    Once you drop the card, the onDrop event fires. This event reverts the isDragging state back to false. The result is as follows:




    • The dragging class is removed from the card

    • The card's original styles are restored



    The styles for the dragging class are defined in the App.css file.






    Defining the drop targets for cards



    To create drop targets for the cards, we first need to set up drop targets where the cards can be dropped. For that purpose, pragmatic-drag-and-drop library provides the dropTargetForElements function to make an element a drop target.



    In our case, we need to make both the cards and columns droppable elements because we want to support reordering within the same column and moving cards between different columns. Making the cards drop targets Let's start by making the card a drop target. First, import the dropTargetForElements function in the Card component, and attach it to the card element to set it up as a drop target:




    CODE
    // rest of the imports
    import {
    draggable,
    dropTargetForElements, // NEW
    } from "@atlaskit/pragmatic-drag-and-drop/element/adapter";
    import { combine } from "@atlaskit/pragmatic-drag-and-drop/combine"; // NEW
    import { attachClosestEdge } from "@atlaskit/pragmatic-drag-and-drop-hitbox/closest-edge"; // NEW

    const Card = ({ children, ...card }) => {
    const cardRef = useRef(null);
    const [isDragging, setIsDragging] = useState(false);

    useEffect(() => {
    const cardEl = cardRef.current;
    invariant(cardEl);

    // Combine draggable and dropTargetForElements cleanup functions
    // to return a single cleanup function
    return combine(
    draggable({
    element: cardEl,
    getInitialData: () => ({ type: "card", cardId: card.id }),
    onDragStart: () => setIsDragging(true),
    onDrop: () => setIsDragging(false),
    }),
    // Add dropTargetForElements to make the card a drop target
    dropTargetForElements({
    element: cardEl,
    getData: ({ input, element }) => {
    // To attach card data to a drop target
    const data = { type: "card", cardId: card.id };

    // Attaches the closest edge (top or bottom) to the data object
    // This data will be used to determine where to drop card relative
    // to the target card.
    return attachClosestEdge(data, {
    input,
    element,
    allowedEdges: ["top", "bottom"],
    });
    },
    getIsSticky: () => true, // To make a drop target "sticky"
    onDragEnter: (args) => {
    if (args.source.data.cardId !== card.id) {
    console.log("onDragEnter", args);
    }
    },
    })
    );
    // Update the dependency array
    }, [card.id]);
    return (
    <div className={`card ${isDragging ? "dragging" : ""}`} ref={cardRef}>
    {children}
    </div>
    );
    };






    We've made some changes to our code to turn the card into a drop target. Let me walk you through each step.



    First, we used the dropTargetForElements function to make the card a drop target by attaching the card element's ref. We also included the getData function to attach the card and closest edge data to the drop target, which we'll use to determine which card a draggable item is dropped onto.



    Next, we added getIsSticky to make the drop target sticky, which is helpful for keeping a selection active while moving between drop targets. Additionally, we attached the onDragEnter event to detect when a draggable item enters the drop target area.



    To manage cleanup efficiently, we combined the cleanup functions of draggable and dropTargetForElements using the combine function provided by the library.



    To test these changes, simply drag one card over another. You'll see detailed logs in your console, including information about the dragged item's data and the drop target. Here's how it looks:




    CODE
    // This log has draggable and drop target data 
    // that we attached using the getData and getInitialData
    // function along with additional information.
    {
    source: {...},
    location: {...},
    self: {...}
    }






    Making the columns drop targets



    Now, let's make all the columns drop targets using the same approach we used for the cards.



    In the Column component, create a ref for the column using useRef. Then, within a useEffect hook, use the invariant function to ensure the column element exists before making it a drop target. Finally, call the dropTargetForElements function like this:




    CODE
    import { useEffect, useRef, useState } from "react"; // NEW
    import invariant from "tiny-invariant"; // NEW
    import { dropTargetForElements } from "@atlaskit/pragmatic-drag-and-drop/element/adapter"; // NEW

    import Card from "./Card";

    const Column = ({ columnId, title, cards }) => {
    const columnRef = useRef(null); // Create a ref for the column
    const [isDraggedOver, setIsDraggedOver] = useState(false);

    useEffect(() => {
    const columnEl = columnRef.current;
    invariant(columnEl); // Ensure the column element exists

    // Set up the drop target for the column element
    return dropTargetForElements({
    element: columnEl,
    onDragStart: () => setIsDraggedOver(true),
    onDragEnter: () => setIsDraggedOver(true),
    onDragLeave: () => setIsDraggedOver(false),
    onDrop: () => setIsDraggedOver(false),
    getData: () => ({ columnId }),
    getIsSticky: () => true,
    });
    }, [columnId]);
    return (
    <div
    className={`column ${isDraggedOver ? "dragged-over" : ""}`}
    ref={columnRef} // attach a columnRef to the column div
    >
    <h2>{title}</h2>
    {cards.map((card) => (
    <Card key={card.id} {...card}>
    {card.content}
    </Card>
    ))}
    </div>
    );
    };






    We've modified our code to make the columns a drop target. Let me guide you through each step.



    First, we created a columnRef using the useRef hook to keep a reference to the column DOM element.



    Next, we used the dropTargetForElements function to make the column a drop target by attaching the column element's ref. We also added the getData function to attach column data to the drop target, which we'll use to determine which column a draggable item is dropped into.



    Additionally, we attached the onDragEnter, onDragStart, onDragLeave, and onDrop events to detect when a draggable item enters, leaves, or is dropped onto the drop target area. These events also update the isDraggedOver state accordingly.



    Finally, we added the dragged-over class when isDraggedOver is true, allowing us to style the column accordingly. To test these changes, try moving a card to a different column, and observe the background color change of the column:  




    1. Dropping on an empty column or spaceWhen you drop a card into an empty column or space, whether within the same column or in a different column, the drop targets will be 1 because one element is involved: the target column itself:



     



    Case 2: Moving between columns by dropping into an empty column or space — drop target: 1 To handle this case, we first need to remove the dragged card from the source column and then insert it into the destination column. First, let's define the moveCard function inside our Board component like this:




    CODE
    const moveCard = useCallback(
    ({
    movedCardIndexInSourceColumn,
    sourceColumnId,
    destinationColumnId,
    movedCardIndexInDestinationColumn,
    }) => {
    // Get data of the source column
    const sourceColumnData = columnsData[sourceColumnId];

    // Get data of the destination column
    const destinationColumnData = columnsData[destinationColumnId];

    // Identify the card to move
    const cardToMove = sourceColumnData.cards[movedCardIndexInSourceColumn];

    // Remove the moved card from the source column
    const newSourceColumnData = {
    ...sourceColumnData,
    cards: sourceColumnData.cards.filter(
    (card) => card.id !== cardToMove.id
    ),
    };

    // Create a copy of the destination column's cards array
    const newDestinationCards = Array.from(destinationColumnData.cards);

    // Determine the new index in the destination column
    const newIndexInDestination = movedCardIndexInDestinationColumn ?? 0;

    // Insert the moved card into the new index in the destination column
    newDestinationCards.splice(newIndexInDestination, 0, cardToMove);

    // Create new destination column data with the moved card
    const newFinishColumnData = {
    ...destinationColumnData,
    cards: newDestinationCards,
    };

    // Update the state with the new columns data
    setColumnsData({
    ...columnsData,
    [sourceColumnId]: newSourceColumnData,
    [destinationColumnId]: newFinishColumnData,
    });
    },
    [columnsData]
    );






    Then call it when the source and destination columns are different:




    CODE
    const handleDrop = useCallback(
    ({ source, location }) => {
    // rest of the code
    if (location.current.dropTargets.length === 1) {
    // check if the source and destination columns are the same
    if (sourceColumnId === destinationColumnId) {
    // rest of the code
    }

    // When columns are different, move the card to the new column
    moveCard({
    movedCardIndexInSourceColumn: draggedCardIndex,
    sourceColumnId,
    destinationColumnId,
    });
    return;
    }
    // rest of the code
    }
    // update the dependency array to include moveCard
    [columnsData, moveCard, reorderCard]
    );






    Now, you'll be able to move cards into empty columns:



    Case 4: Moving between columns by dropping onto another card — drop target: 2 To handle this case, we first need to remove the moved card from the source column and then insert it relative to the target card in a different column. We can use the moveCard function again to move the cards, but this time, we’ll pass the value of movedCardIndexInDestinationColumn to the moveCard function:




    CODE
    if (location.current.dropTargets.length === 2) {
    // rest of the code

    // Check if the source and destination columns are the same
    if (sourceColumnId === destinationColumnId) {
    // rest of the code
    }
    // Determine the new index for the moved card in the destination column.
    const destinationIndex =
    closestEdgeOfTarget === "bottom"
    ? indexOfTarget + 1
    : indexOfTarget;

    moveCard({
    movedCardIndexInSourceColumn: draggedCardIndex,
    sourceColumnId,
    destinationColumnId,
    movedCardIndexInDestinationColumn: destinationIndex,
    });
    }






    Now, you should be able to move cards between columns by dropping onto another card.






    Add drop indicator



    To improve the user experience, adding a drop indicator can be very helpful. A drop indicator visually shows where the dragged item will be placed when dropped.



    To implement a drop indicator, first, create a new component called DropIndicator.js in the components folder. This component will render a visual indicator where the item will be dropped:




    CODE
    const DropIndicator = ({ edge, gap }) => {
    const edgeClassMap = {
    top: "edge-top",
    bottom: "edge-bottom",
    };

    const edgeClass = edgeClassMap[edge];

    const style = {
    "--gap": gap,
    };

    return <div className={`drop-indicator ${edgeClass}`} style={style}></div>;
    };

    export default DropIndicator;






    You can find the styling for the DropIndicator component in the App.css file.



    Now, import the DropIndicator component in the Card component, and add logic to show the indicator when a card is being dragged over:




    CODE
    // rest of the imports
    import {
    attachClosestEdge,
    extractClosestEdge, // NEW
    } from "@atlaskit/pragmatic-drag-and-drop-hitbox/closest-edge";
    import DropIndicator from "./DropIndicator"; // NEW

    const Card = ({ children, ...card }) => {
    // rest of the state variables

    // State to track the closest edge during drag over
    const [closestEdge, setClosestEdge] = useState(null); // NEW

    useEffect(() => {
    // rest of the code
    return combine(
    draggable({
    /*...*/
    }),
    dropTargetForElements({
    element: cardEl,
    getData: ({ input, element }) => {
    // rest of the code
    },
    getIsSticky: () => true,
    // NEW
    onDragEnter: (args) => {
    // Update the closest edge when a draggable item enters the drop zone
    if (args.source.data.cardId !== card.id) {
    setClosestEdge(extractClosestEdge(args.self.data));
    }
    },
    onDrag: (args) => {
    // Continuously update the closest edge while dragging over the drop zone
    if (args.source.data.cardId !== card.id) {
    setClosestEdge(extractClosestEdge(args.self.data));
    }
    },
    onDragLeave: () => {
    // Reset the closest edge when the draggable item leaves the drop zone
    setClosestEdge(null);
    },
    onDrop: () => {
    // Reset the closest edge when the draggable item is dropped
    setClosestEdge(null);
    },
    })
    );
    }, [card.id]);
    return (
    <div className={`card ${isDragging ? "dragging" : ""}`} ref={cardRef}>
    {children}
    {/* render the DropIndicator if there's a closest edge */}
    {closestEdge && <DropIndicator edge={closestEdge} gap="8px" />}
    </div>
    );
    };






    Now, when you drag a card over another card, you should see a drop indicator showing where the card will be placed: : Debug JavaScript errors more easily by understanding the context


    Debugging code is always a tedious task. But the more you understand your errors, the easier it is to fix them.





    LogRocket records console logs, page load times, stack traces, slow network requests/responses with headers + bodies, browser metadata, and custom logs. Understanding the impact of your JavaScript code will never be easier!



    Try it for free.

    Vollständiger Original-Artikel
    Den kompletten Beitrag mit allen Details direkt auf dev.to lesen.
    ↗ Original-Artikel auf dev.to lesen
Wie bewertest du diesen Beitrag?
1 Klick Feedback
Teilen mit Netzwerk & Team:

Community-Analysen & Experten-Meinungen 0

Verfasse deine eigene Analyse, teile Workarounds oder diskutiere diesen Vorfall im Blog.
Noch keine Community-Analyse verfasst. Markiere einen Textabschnitt oder klicke oben auf Eigene Analyse verfassen“!
Community Pulse: Relevanz-Einschätzung
1 Klick Experten-Votum
🔴 Akute Relevanz 0%
🟡 In Evaluierung 0%
🟢 Keine Auswirkung 0%
Spannende Innovation 0%
Verwandte Story-Cluster & Quellen (Vektor-KI)
Port 8095 Engine
2 Quellen
CVE-2026-88255 | ZenHive mpp up to 0.16.1 Duplicate Submission Gate lib/mpp/replay.ex reserve_hash_atomic input validation (EUVD-2026-80256)
1 Quelle
Android 17: Neue Version ist hier – Das ist alles neu
1 Quelle
Die entscheidende Hürde: Xpeng will deutsch und nicht chinesisch sein
Ähnliche Beiträge
🔍 Verwandte News

Auch interessante Nachrichten Implement the Pragmatic drag and drop library

Thematisch verwandte Begriffe: Implement, Pragmatic, drag, drop · 6 Treffer

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...