A modern, lightweight, performant, accessible and extensible drag & drop toolkit for React.

Overview

dnd kit – There's a new kit on the block.

Overview

Build status Stable Release gzip size

  • Built for React: exposes hooks such as useDraggable and useDroppable, and won't require you to re-architect your app or create additional wrapper DOM nodes.
  • Feature packed: customizable collision detection algorithms, multiple activators, draggable overlay, drag handles, auto-scrolling, constraints, and so much more.
  • Supports a wide range of use cases: vertical lists, horizontal lists, grids, multiple containers, nested contexts, variable sized list and grids, transformed items, virtualized lists.
  • Zero dependencies and modular: the core of the library weighs around 10kb minified and has no external dependencies. It's built around built-in React state management and context, which keeps the library lean.
  • Built-in support for multiple input methods: Pointer, mouse, touch and keyboard sensors.
  • Fully customizable & extensible: Customize every detail: animations, transitions, behaviours, styles. Build your own sensors, collision detection algorithms, customize key bindings and so much more.
  • Accessibility: Keyboard support, sensible default aria attributes, customizable screen reader instructions and live regions built-in.
  • Performance: It was built with performance in mind in order to support silky smooth animations.
  • Presets: Need to build a sortable interface? Check out @dnd-kit/sortable, which is a thin layer built on top of @dnd-kit/core. More presets coming in the future.

Documentation

To learn how to get started with dnd kit, visit the official documentation website. You'll find in-depth API documentation, tips and guides to help you build drag and drop interfaces.

View documntation

Playful illustration of draggable and droppable concepts

Key concepts

The core library of dnd kit exposes two main concepts:

Augment your existing components using the useDraggable and useDroppable hooks, or combine both to create components that can both be dragged and dropped over.

Handle events and customize the behaviour of your draggable elements and droppable areas using the provider. Configure sensors to handle different input methods.

Use the component to render a draggable overlay that is removed from the normal document flow and is positioned relative to the viewport.

Check out our quick start guide to learn how get started.

Extensibility

Extensibility is at the core of dnd kit. It was built is built to be lean and extensible. It ships with the features we believe most people will want most of the time, and provides extension points to build the rest on top of @dnd-kit/core.

A prime example of the level of extensibility of dnd kit is the Sortable preset, which is built using the extension points that are exposed by @dnd-kit/core.

The primary extension points of dnd kit are:

  • Sensors
  • Modifiers
  • Constraints
  • Custom collision detection algorithms

Accessibility

Building accessible drag and drop interfaces is hard; dnd kit has a number of sensible defaults and starting points to help you make your drag and drop interface accessible:

  • Customizable screen reader instructions for how to interact with draggable items
  • Customizable live region updates to provide screen reader announcements in real-time of what is currently happening with draggable and droppable elements.
  • Sensible defaults for aria attributes that should be passed to draggable items

Check out our Accessibility guide to learn more about how you can help provide a better experience for screen readers.

Architecture

Unlike most drag and drop libraries, dnd kit intentionally is not built on top of the HTML5 Drag and drop API. This was a deliberate architectural decision, that does come with tradeoffs that you should be aware of before deciding to use it, but for most applications, we believe the benefits outweigh the tradeoffs.

The HTML5 Drag and drop API has some severe limitations. It does not support touch devices, which means that the libraries that are built on top of it need to expose an entirely different implementation to support touch devices. This typically increases the complexity of the codebase and the overall bundle size of the library. Further, it requires workarounds to implement common use cases such as customizing the drag preview, locking dragging to a specific axis or to the bounds of a container, or animating the dragged item as it is picked up.

The main tradeoff with not using the HTML5 Drag and drop API is that you won't be able to drag from the desktop or between windows. If the drag and drop use-case you have in mind involves this kind of functionality, you'll definitely want to use a library that's built on top of the HTML 5 Drag and drop API. We highly recommend you check out react-dnd for a React library that's has a native HTML 5 Drag and drop backend.

Performance

Minimizing DOM mutations

dnd kit lets you build drag and drop interfaces without having to mutate the DOM every time an item needs to shift position.

This is possible because dnd kit lazily calculates and stores the initial positions and layout of your droppable containers when a drag operation is initiated. These positions are passed down to your components that use useDraggable and useDroppable so that you can compute the new positions of your items while a drag operation is underway, and move them to their new positions using performant CSS properties that do not trigger a repaint such as translate3d and scale. For an example of how this can be achieved, check out the implementation of the sorting strategies that are exposed by the @dnd-kit/sortable library.

This isn't to say that you can't shift the position of the items in the DOM while dragging, this is something that is supported and sometimes inevitable. In some cases, it won't be possible to know in advance what the new position and layout of the item until you move it in the DOM. Just know that these kind of mutations to the DOM while dragging are much more expensive and will cause a repaint, so if possible, prefer computing the new positions using translate3d and scale.

Synthetic events

dnd kit also uses SyntheticEvent listeners for the activator events of all sensors, which leads to improved performance over manually adding event listeners to each individual draggable node.

Working in the @dnd-kit repository

Packages contained within this repository

  • @dnd-kit/core
  • @dnd-kit/accessibility
  • @dnd-kit/sortable
  • @dnd-kit/modifiers
  • @dnd-kit/utilities

Installing dependencies

You'll need to install all the dependencies in the root directory. Since the @dnd-kit is a monorepo that uses Lerna and Yarn Workspaces, npm CLI is not supported (only yarn).

yarn install

This will install all dependencies in each project, build them, and symlink them via Lerna

Development workflow

In one terminal, run yarn start in parallel:

yarn start

This builds each package to //dist and runs the project in watch mode so any edits you save inside //src cause a rebuild to //dist. The results will stream to to the terminal.

Running storybook

yarn start:storybook

Runs the storybook Open http://localhost:6006 to view it in the browser.

Screenshot of Storybook running locally

Working with the playground

You can play with local packages in the Parcel-powered playground.

yarn start:playground

This will start the playground on localhost:1234. If you have lerna running watch in parallel mode in one terminal, and then you run parcel, your playground will hot reload when you make changes to any imported module whose source is inside of packages/*/src/*. Note that to accomplish this, each package's start command passes TDSX the --noClean flag. This prevents Parcel from exploding between rebuilds because of File Not Found errors.

Important Safety Tip: When adding/altering packages in the playground, use alias object in package.json. This will tell Parcel to resolve them to the filesystem instead of trying to install the package from NPM. It also fixes duplicate React errors you may run into.

Running Cypress

(In a third terminal) you can run Cypress and it will run the integration tests against storybook.

Comments
  • Provide mouse position to collision detection algorithm

    Provide mouse position to collision detection algorithm

    First off just wanted to say thanks for building this! Loving it so far and I've barely got it working.

    My goal is to implement a version of useSortable that also allows dropping something inside another target.

    I'm still working on this, but I believe in order to do so, I need to use a collision detection algorithm that takes into account the position of the cursor inside the dragging item since it's frequently the case that the draggable is over a droppable, but the cursor is not.

    Any advice on how to achieve this with the existing architecture? Is the mouse position already being tracked somewhere that could be passed?

    opened by jamesopti 29
  • Documentation code for Sortable with Typescript not working

    Documentation code for Sortable with Typescript not working

    I am playing around with the library in a project (which uses TypeScript).

    The code in the Quick start section for a simple drag-and-drop works, but with this code, nothing moves and there is no interactivity.

    I am going on a few hours without being able to find out what is wrong. I would be very happy to accept some pointers :)

    The code below contains two components that are to a large extent just taken stright out of the documentation for Sortable.

    There are no errors in the console, and everything compiles.

    import { DndContext, MouseSensor, useSensor, useSensors } from "@dnd-kit/core";
    import { arrayMove, SortableContext, useSortable } from "@dnd-kit/sortable";
    import { CSS } from "@dnd-kit/utilities";
    import React, { ReactNode, useState } from "react";
    
    export const ExpSortable = () => {
      const [items, setItems] = useState(["1", "2", "3"]);
      const sensors = useSensors(
        useSensor(MouseSensor, {
          activationConstraint: {
            distance: 10
          }
        })
      );
    
      return (
        <DndContext sensors={sensors} onDragEnd={handleDragEnd}>
          <SortableContext items={items}>
            {items.map((id) => (
              <SortableItem key={id} id={id}>
                <p>hello from {id}</p>
              </SortableItem>
            ))}
          </SortableContext>
        </DndContext>
      );
    
      function handleDragEnd(event: any) {
        const { active, over } = event;
        console.log("drag end!");
        if (active.id !== over.id) {
          setItems((items) => {
            const oldIndex = items.indexOf(active.id);
            const newIndex = items.indexOf(over.id);
            return arrayMove(items, oldIndex, newIndex);
          });
        }
      }
    };
    
    export function SortableItem(props: { children?: ReactNode; id: string }) {
      const { listeners, setNodeRef, transform, transition } = useSortable({
        id: props.id
      });
    
      const style = {
        padding: "5vmin",
        background: "orange",
        border: "2px solid",
        transform: CSS.Transform.toString(transform),
        transition
      } as React.CSSProperties;
    
      return (
        <div ref={setNodeRef} style={style} {...listeners}>
          {props.children}
        </div>
      );
    }
    
    
    opened by ludwignagelhus 22
  • 'Maximum update depth exceeded' error with Sortable

    'Maximum update depth exceeded' error with Sortable

    Here is an example: https://codesandbox.io/s/dnd-kit-issue-eq952

    https://user-images.githubusercontent.com/7955306/139406591-7a542b60-c578-485f-9058-8abe8f376e5b.mov

    The problem is because of items filtering. But if we remove it we get empty space when move item out of the container

    const filteredItems = activeId && isOutOfContainer ? items.filter((item) => item !== activeId) : items;

    https://user-images.githubusercontent.com/7955306/139406934-653e5071-a45e-42fd-9d45-5c52222f8017.mov

    opened by Dm1Korneev 16
  • RectIntersection is not working with draggable items inside a scrollable container

    RectIntersection is not working with draggable items inside a scrollable container

    The draggable items that are scrolled are not calculating the intersectionRatio correctly.

    Please, see this code sandbox for an example: https://codesandbox.io/s/react-dnd-grid-0ylzl?file=/src/App.js

    NOTE: Try dragging the last draggable item into one droppable area.

    bug sponsored 
    opened by jeserodz 16
  • perf regression: all Sortables in 5.0 rerender constantly on even smallest mouse movement

    perf regression: all Sortables in 5.0 rerender constantly on even smallest mouse movement

    Hi there. Thanks for this amazing, composable library. We are upgrading from 4.0 to 5.0 and noticed a performance regression. Each Sortable now rerenders constantly on even the smallest mouse movement. This is visible by turning rerender indicators on in react dev tools and visiting an example Sortable story:

    https://user-images.githubusercontent.com/3527177/153221284-20794b8f-9384-439a-acf8-25a0b343adf7.mov

    In previous versions the Sortables do not rerender unless there is a change on the over state. This would be the expected behavior:

    https://user-images.githubusercontent.com/3527177/153223557-ec66c6eb-95ed-4a77-9148-f5a28312cf1f.mov

    opened by dontsave 14
  • Unnecessary rerenders cause poor performance

    Unnecessary rerenders cause poor performance

    Our application has many droppable and draggable components displayed at once and is suffering from poor performance when dragging. When the dragged element crosses over a droppable, it causes all of our draggable and droppable components to rerender for seemingly no reason.

    Here's a code sandbox that demonstrates the issue. Each Draggable/Droppable displays the number of times it has rendered. You'll notice that when dragging one of the red boxes, the render count of the other Draggable and Droppable components increases even though their props have not changed.

    Code Sandbox

    The performance of the code sandbox is actually fine, but the unnecessary rerenders cause performance issues in our app because the draggables are expensive to rerender (something we could probably fix).

    I'm not sure if this is expected behavior or a bug. If it does seem to be a fixable problem I would be happy to attempt a PR if you provide some direction.

    P.S. Great library!

    opened by srmagura 13
  • does `useSortable` support different draggable types?

    does `useSortable` support different draggable types?

    It isn't entirely clear from the Docs, but currently in Multiple Containers - Basic Setup is it also possible to sort the droppable(container) as well? Thereby achieving a Kanban like app?


    I'm wondering if it's possible to use dnd-kit to replicate this behavior?

    i.e. boards can be sorted and combined, board items can also be sorted and combined.

    opened by cusxio 13
  • Wrong top calculation for scroll ancestors with fixed position?

    Wrong top calculation for scroll ancestors with fixed position?

    Hi there, we're using the library to create a dnd experience between a scrollable fixed position div and a sortable ( scrollable ) drop zone. This mostly works well ( we're currently using PR #54 as our basis ) but causes our DragOverlay to appear in the wrong top position after scrolling the drop zone.

    Below is an example based on the sandbox shown in #43 scroll-fixed-3 https://codesandbox.io/s/react-dnd-grid-forked-gls5l?file=/src/App.js

    We made a change to check whether an element ancestor is fixed in getScrollableAncestors, which causes only that ancestor to be returned ( Obviously, this is just a small demo and doesn't deal with more complex scenarios / performance etc.)

    https://github.com/bbenzikry/dnd-kit/blob/a2cd7052c1cdf04e05af936127650b1dd6db7485/packages/core/src/utilities/scroll/getScrollableAncestors.ts#L22-L26

    This makes the following return the expected value for our scenario https://github.com/clauderic/dnd-kit/blob/d13d28471ec7716f08e211647cad89ae3c11dd06/packages/core/src/utilities/rect/getRect.ts#L82-L84

    bug 
    opened by bbenzikry 12
  • Glitchy animation when dropping item

    Glitchy animation when dropping item

    Hi, I am experiencing a weird animation when sorting a list of elements. I cannot provide the exact codebase, but I have built it on top of the story presets > sortable > multiple containers > many items.

    Here below you can see a video of the problem. Notice how the<DragOverlay /> falls correctly into place, while the remaining elements shifts up in a weird way.

    https://user-images.githubusercontent.com/12138301/170713994-dcf7dbbc-0bea-4e37-b107-e7b51cef15a2.mov

    I have spent quite some time trying to track down the problem, but with no result so far. Anybody has idea of what could be the cause?

    Thanks.

    more information required needs reproduction case 
    opened by MTxx87 11
  • Sortable - onClick event fired when moving a SortableItem to a lower index

    Sortable - onClick event fired when moving a SortableItem to a lower index

    Hi !

    I'm facing an issue using sortable: when I'm moving a SortableItem from right to left, the onClick event is fired along the onDragEnd event. This isn't happing if I'm moving my item to the right.

    Here is the simple sample of code I'm using:

                  <DndContext
                        sensors={sensors}
                        collisionDetection={closestCenter}
                        onDragEnd={handleDragEnd}
                        modifiers={[restrictToParentElement]}
                    >
                        <SortableContext
                            items={displayedArticles.map(article => article.id)}
                            strategy={rectSortingStrategy}
                        >
                            {displayedArticles.map(article => (
                                <Article
                                    key={article.id}
                                    name={article.name}
                                    id={article.id}
                                    onDeleteClick={() => {
                                        setArticleToDelete(article.id);
                                    }}
                                    onClick={() => console.log('onClick fired')}
                                />
                            ))}
                            <Add onClick={onOpen} />
                        </SortableContext>
                    </DndContext>
    

    And here is a video of what's happening: ezgif com-gif-maker (1)

    Is this an expected behavior ? Do I miss something ? Is there a way to completely silent onClick when the Item has been dragged ?

    Thank you !

    bug has workaround 
    opened by lonk 11
  • Grid sort: the sortable box redraw when the box picked up

    Grid sort: the sortable box redraw when the box picked up

    For grid sort, I have 2x large box and 1x small box in the grid. All the boxes redraw when the sortable box picked up. The react-sortable-hoc package only sort and redraw when handleDragEnd. Sometimes, the box will blinking when drag over.

    The screenshot: https://user-images.githubusercontent.com/8286468/112081091-10647c00-8bbe-11eb-9421-e1e4954a44da.mp4 Code: https://codesandbox.io/s/dndkit-sortable-image-grid-forked-j7ent?file=/src/App.jsx:1543-1557

    opened by smurfs2549 11
  • Scroll controller

    Scroll controller

    I'm trying to create a draggable item (or similar) to control the horizontal scrolling of a container. I have searched the documentation and issues extensively but haven't been able to find anything.

    I would like draggable item that you can click and drag horizontally to scroll the container. The further I drag the item from center the faster the container scrolls. When I release the item, it should center itself.

    It would be very much appreciated if anyone could point me in the right direction to solve this.

    Scroll controller

    opened by johnnyduncan 0
  • @dnd-kit not allowing to prevent dragging items

    @dnd-kit not allowing to prevent dragging items

    I'm using this npm package: @dnd-kit https://github.com/clauderic/dnd-kit to be able to drag drop elements up and down in a vertical list. Dragging elements works perfect for me. My problem is that based on some condition I need to block the dragging of the elements at all.

    To reproduce the issue you can follow these steps:

    $ git clone https://github.com/clauderic/dnd-kit
    $ cd dnd-kit
    $ git checkout master # currently: d5c4732d7262c773db338850e9b2bb386c938ddf
    $ yarn
    $ yarn start:storybook
    

    On file: /stories/2 - Presets/Sortable/1-Vertical.story.tsx, just add the highlighted text on the screenshot below...

    [enter image description here]1

    Here is the added text so you can copy paste:

    export const LockedBothAxis = () => (
      <Sortable
        {...props}
        modifiers={[restrictToHorizontalAxis, restrictToVerticalAxis, restrictToWindowEdges]}
      />
    );
    

    where you can see my intention is to block the dragging on both axis: horizontal and vertical. Whenever the block condition is true I tried by using those 2 modifiers above: { restrictToHorizontalAxis, restrictToVerticalAxis } (which doesn't totally work).

    Now go to: http://localhost:6006/?path=/story/presets-sortable-vertical--locked-both-axis and try to drag the items.

    If you try a short distance dragging then you will notice the dragging doesn't work (so far so good).

    My problem is: If you try a long distance dragging (all the way up or down) then you will notice that you can actually drag the items.

    What I need: When the user long presses an item, the item gets highlighted but when he tries a short or a long distance dragging, the item doesn't get dragged.

    Below you have a demostration of my issue, where I try first a short distance dragging up and down and the item doesn't get dragged (so far so good). But later I try a long distance dragging down and the item gets dragged (my issue)...

    [enter image description here]2

    Any idea on how to block the dragging at all even if the user does a long distance dragging?

    opened by zeuscronos 0
  • Refactor storybook for easy comprehension

    Refactor storybook for easy comprehension

    There's no much content available about developing different kinds of interfaces using the library, so it would be nice to be able to use storybook source code for reference. The god class reference that's used on storybook makes it nearly impossible to find and extract the wanted behaviour. Please, separate it in smaller pieces so we can rely on it without wondering what parts of the boilerplate does what we intent to do

    opened by RodrigoNovais 0
  • Disabling `scrollIntoView` as a optional prop in `DragOverlay`

    Disabling `scrollIntoView` as a optional prop in `DragOverlay`

    First of all, thank you for creating such a great tool! So many options and possibilities to customize! ❤️

    I'd like to propose an improvement to DragOverlay component which would make it much easier to customize the useDropAnimation function.

    Recently, I've been trying to customize dropAnimation to disable scrolling into view after dropping the active element. Turns out, I'd have to override the whole useDropAnimation function to disable just that. I'd like to keep drop animation but without scrolling.

    A control over scrolling to view would solve the problem when two or more users are working on a multi-container board. Dropping the active item causes abrupt scrolling after updating one user's board. This looks fine for the user who dropped the item, but for another user, it may break their current workflow.

    It could be another option in dropAnimation property. @clauderic please let me know what you think of that. Maybe you have another simpler way to customize just the scrolling behavior?

    opened by martaradziszewska 1
  • How to simulate drag and drop with animation

    How to simulate drag and drop with animation

    I have a use case that I don't find any resources except on test libraries, but thoses seem over complicated for my use case.

    I just wan't to trigger the drag animation of an item from a container to another (sortable) container, only by code.

    The idea is to fire this with a right-click. So the user will have the abilitie to drag & drop manually, or to right-click to achieve the transfer faster.

    Thank for helping me with this nice library !

    opened by Raphael-Bahuau 0
  • DndContext isolation of concerns

    DndContext isolation of concerns

    In my use-case, items need to be "sortable" when dragged via handle icon, and need to be draggable outside of container when dragging the entire item.

    Is there a way to implement these two different features separately from one another? Via 2 different DndContexts which know nothing of one another? One managing sort order change with its onDragEnd event, and the other one handing the drag-n-drop elsewhere with its events.

    opened by estorski 0
Releases(@dnd-kit/[email protected])
  • @dnd-kit/[email protected](Dec 7, 2022)

  • @dnd-kit/[email protected](Dec 7, 2022)

  • @dnd-kit/[email protected](Dec 7, 2022)

  • @dnd-kit/[email protected](Jun 14, 2022)

  • @dnd-kit/[email protected](Jun 14, 2022)

  • @dnd-kit/[email protected](Jun 14, 2022)

  • @dnd-kit/[email protected](May 30, 2022)

    Patch Changes

    • #776 3978c43 Thanks @clauderic! - The ARIA live region element used for screen reader announcements is now positioned using position: fixed instead of position: absolute. As of @dnd-kit/core^6.0.0, the live region element is no longer portaled by default into the document.body. This change was introduced in order to fix issues with portaled live regions. However, this change can introduce visual regressions when using absolutely positioned elements, since the live region element is constrained to the stacking and position context of its closest positioned ancestor. Using fixed position ensures the element does not introduce visual regressions.
    Source code(tar.gz)
    Source code(zip)
  • @dnd-kit/cor[email protected](May 29, 2022)

    Patch Changes

    • #772 e97cb1f Thanks @clauderic! - The ARIA live region element used for screen reader announcements is now positioned using position: fixed instead of position: absolute. As of @dnd-kit/core^6.0.0, the live region element is no longer portaled by default into the document.body. This change was introduced in order to fix issues with portaled live regions. However, this change can introduce visual regressions when using absolutely positioned elements, since the live region element is constrained to the stacking and position context of its closest positioned ancestor. Using fixed position ensures the element does not introduce visual regressions.
    Source code(tar.gz)
    Source code(zip)
  • @dnd-kit/[email protected](May 27, 2022)

    Patch Changes

    • #769 8e3599f Thanks @clauderic! - Fixed an issue with the containerNodeRect that is exposed to modifiers having stale properties (top, left, etc.) when its scrollable ancestors were scrolled.

    • #769 53cb962 Thanks @clauderic! - Fixed a regression with scrollable ancestors detection.

      The scrollable ancestors should be determined by the active node or the over node exclusively. The draggingNode variable shouldn't be used to detect scrollable ancestors since it can be the drag overlay node, and the drag overlay node doesn't have any scrollable ancestors because it is a fixed position element.

    Source code(tar.gz)
    Source code(zip)
  • @dnd-kit/[email protected](May 21, 2022)

  • @dnd-kit/[email protected](May 21, 2022)

    Major Changes

    • #755 33e6dd2 Thanks @clauderic! - The UniqueIdentifier type has been updated to now accept either string or number identifiers. As a result, the id property of useDraggable, useDroppable and useSortable and the items prop of <SortableContext> now all accept either string or number identifiers.

      Migration steps

      For consumers that are using TypeScript, import the UniqueIdentifier type to have strongly typed local state:

      + import type {UniqueIdentifier} from '@dnd-kit/core';
      
      function MyComponent() {
      -  const [items, setItems] = useState(['A', 'B', 'C']);
      +  const [items, setItems] = useState<UniqueIdentifier>(['A', 'B', 'C']);
      }
      

      Alternatively, consumers can cast or convert the id property to a string when reading the id property of interfaces such as Active, Over, DroppableContainer and DraggableNode.

      The draggableNodes object has also been converted to a map. Consumers that were reading from the draggableNodes property that is available on the public context of <DndContext> should follow these migration steps:

      - draggableNodes[someId];
      + draggableNodes.get(someId);
      
    • #660 30bbd12 Thanks @clauderic! - Changes to the default sortableKeyboardCoordinates KeyboardSensor coordinate getter.

      Better handling of variable sizes

      The default sortableKeyboardCoordinates function now has better handling of lists that have items of variable sizes. We recommend that consumers re-order lists onDragOver instead of onDragEnd when sorting lists of variable sizes via the keyboard for optimal compatibility.

      Better handling of overlapping droppables

      The default sortableKeyboardCoordinates function that is exported from the @dnd-kit/sortable package has been updated to better handle cases where the collision rectangle is overlapping droppable rectangles. For example, for down arrow key, the default function had logic that would only consider collisions against droppables that were below the bottom edge of the collision rect. This was problematic when the collision rect was overlapping droppable rects, because it meant that it's bottom edge was below the top edge of the droppable, and that resulted in that droppable being skipped.

      - collisionRect.bottom > droppableRect.top
      + collisionRect.top > droppableRect.top
      

      This change should be backwards compatible for most consumers, but may introduce regressions in some use-cases, especially for consumers that may have copied the multiple containers examples. There is now a custom sortable keyboard coordinate getter optimized for multiple containers that you can refer to.

    Minor Changes

    • #748 59ca82b Thanks @clauderic! - Automatic focus management and activator node refs.

      Introducing activator node refs

      Introducing the concept of activator node refs for useDraggable and useSortable. This allows @dnd-kit to handle common use-cases such as restoring focus on the activator node after dragging via the keyboard or only allowing the activator node to instantiate the keyboard sensor.

      Consumers of useDraggable and useSortable may now optionally set the activator node ref on the element that receives listeners:

      import {useDraggable} from '@dnd-kit/core';
      
      function Draggable(props) {
        const {
          listeners,
          setNodeRef,
      +   setActivatorNodeRef,
        } = useDraggable({id: props.id});
      
        return (
          <div ref={setNodeRef}>
            Draggable element
            <button
              {...listeners}
      +       ref={setActivatorNodeRef}
            >
              :: Drag Handle
            </button>
          </div>
        )
      }
      

      It's common for the activator element (the element that receives the sensor listeners) to differ from the draggable node. When this happens, @dnd-kit has no reliable way to get a reference to the activator node after dragging ends, as the original event.target that instantiated the sensor may no longer be mounted in the DOM or associated with the draggable node that was previously active.

      Automatically restoring focus

      Focus management is now automatically handled by @dnd-kit. When the activator event is a Keyboard event, @dnd-kit will now attempt to automatically restore focus back to the first focusable node of the activator node or draggable node.

      If no activator node is specified via the setActivatorNodeRef setter function of useDraggble and useSortable, @dnd-kit will automatically restore focus on the first focusable node of the draggable node set via the setNodeRef setter function of useDraggable and useSortable.

      If you were previously managing focus manually and would like to opt-out of automatic focus management, use the newly introduced restoreFocus property of the accessibility prop of <DndContext>:

      <DndContext
        accessibility={{
      +   restoreFocus: false
        }}
      
    • #672 10f6836 Thanks @clauderic! - SortableContext now always requests measuring of droppable containers when its items prop changes, regardless of whether or not dragging is in progress. Measuring will occur if the measuring configuration allows for it.

    • #754 224201a Thanks @clauderic! - The <SortableContext> component now optionally accepts a disabled prop to globally disable useSortable hooks rendered within it.

      The disabled prop accepts either a boolean or an object with the following shape:

      interface Disabled {
        draggable?: boolean;
        droppable?: boolean;
      }
      

      The useSortable hook has now been updated to also optionally accept the disabled configuration object to conditionally disable the useDraggable and/or useDroppable hooks used internally.

      Like the strategy prop, the disabled prop defined on the useSortable hook takes precedence over the disabled prop defined on the parent <SortableContext>.

    Patch Changes

    Source code(tar.gz)
    Source code(zip)
  • @dnd-kit/[email protected](May 21, 2022)

  • @dnd-kit/[email protected](May 21, 2022)

    Major Changes

    • #746 4173087 Thanks @clauderic! - Accessibility related changes.

      Regrouping accessibility-related props

      Accessibility-related props have been regrouped under the accessibility prop of <DndContext>:

      <DndContext
      - announcements={customAnnouncements}
      - screenReaderInstructions={customScreenReaderInstructions}
      + accessibility={{
      +  announcements: customAnnouncements,
      +  screenReaderInstructions: customScreenReaderInstructions,
      + }}
      

      This is a breaking change that will allow easier addition of new accessibility-related features without overloading the props namespace of <DndContext>.

      Arguments object for announcements

      The arguments passed to announcement callbacks have changed. They now receive an object that contains the active and over properties that match the signature of those passed to the DragEvent handlers (onDragStart, onDragMove, etc.). This change allows consumers to read the data property of the active and over node to customize the announcements based on the data.

      Example migration steps:

      export const announcements: Announcements = {
      -  onDragStart(id) {
      +  onDragStart({active}) {
      -    return `Picked up draggable item ${id}.`;
      +    return `Picked up draggable item ${active.id}.`;
        },
      -  onDragOver(id, overId) {
      +  onDragOver({active, over}) {
      -    if (overId) {
      +    if (over) {
      -      return `Draggable item ${id} was moved over droppable area ${overId}.`;
      +      return `Draggable item ${active.id} was moved over droppable area ${over.id}.`;
          }
      
      -    return `Draggable item ${id} is no longer over a droppable area.`;
      +    return `Draggable item ${active.id} is no longer over a droppable area.`;
        },
      };
      

      Accessibility-related DOM nodes are no longer portaled by default

      The DOM nodes for the screen reader instructions and announcements are no longer portaled into the document.body element by default.

      This change is motivated by the fact that screen readers do not always announce ARIA live regions that are rendered on the document.body. Common examples of this include when rendering a <DndContext> within a <dialog> element or an element that has role="dialog", only ARIA live regions rendered within the dialog will be announced.

      Consumers can now opt to render announcements in the portal container of their choice using the container property of the accessibility prop:

      <DndContext
      + accessibility={{
      +  container: document.body,
      + }}
      
    • #733 035021a Thanks @clauderic! - The <DragOverlay> component's drop animation has been refactored, which fixes a number of bugs with the existing implementation and introduces new functionality.

      What's new?

      Scrolling the draggable node into view if needed

      The drop animation now ensures that the the draggable node that we are animating to is in the viewport before performing the drop animation and scrolls it into view if needed.

      Changes to the dropAnimation prop

      The dropAnimation prop of <DragOverlay> now accepts either a configuration object or a custom drop animation function.

      The configuration object adheres to the following shape:

      interface DropAnimationOptions {
        duration?: number;
        easing?: string;
        keyframes?: DropAnimationKeyframeResolver;
        sideEffects?: DropAnimationSideEffects;
      }
      

      The default drop animation options are:

      const defaultDropAnimationConfiguration: DropAnimationOptions = {
        duration: 250,
        easing: 'ease',
        keyframes: defaultDropAnimationKeyframes,
        sideEffects: defaultDropAnimationSideEffects({
          styles: {
            active: {
              opacity: '0',
            },
          },
        }),
      };
      

      The keyframes option allows consumers to override the keyframes of the drop animation. For example, here is how you would add a fade out transition to the drop animation using keyframes:

      import {CSS} from '@dnd-kit/utilities';
      
      const customDropAnimation = {
        keyframes({transform}) {
          return [
            {opacity: 1, transform: CSS.Transform.toString(transform.initial)},
            {opacity: 0, transform: CSS.Transform.toString(transform.final)},
          ];
        },
      };
      

      The dragSourceOpacity option has been deprecated in favour of letting consumers define arbitrary side effects that should run before the animation starts. Side effects may return a cleanup function that should run when the drop animation has completed.

      type CleanupFunction = () => void;
      
      export type DropAnimationSideEffects = (
        parameters: DropAnimationSideEffectsParameters
      ) => CleanupFunction | void;
      

      Drop animation side effects are a powerful abstraction that provide a lot of flexibility. The defaultDropAnimationSideEffects function is exported by @dnd-kit/core and aims to facilitate the types of side-effects we anticipate most consumers will want to use out of the box:

      interface DefaultDropAnimationSideEffectsOptions {
        // Apply a className on the active draggable or drag overlay node during the drop animation
        className?: {
          active?: string;
          dragOverlay?: string;
        };
        // Apply temporary styles to the active draggable node or drag overlay during the drop animation
        styles?: {
          active?: Styles;
          dragOverlay?: Styles;
        };
      }
      

      For advanced side-effects, consumers may define a custom sideEffects function that may optionally return a cleanup function that will be executed when the drop animation completes:

      const customDropAnimation = {
        sideEffects({active}) {
          active.node.classList.add('dropAnimationInProgress');
          active.node.animate([{opacity: 0}, {opacity: 1}], {
            easing: 'ease-in',
            duration: 250,
          });
      
          return () => {
            // Clean up when the drop animation is complete
            active.node.classList.remove('dropAnimationInProgress');
          };
        },
      };
      

      For even more advanced use-cases, consumers may also provide a function to the dropAnimation prop, which adheres to the following shape:

      interface DropAnimationFunctionArguments {
        active: {
          id: UniqueIdentifier;
          data: DataRef;
          node: HTMLElement;
          rect: ClientRect;
        };
        draggableNodes: DraggableNodes;
        dragOverlay: {
          node: HTMLElement;
          rect: ClientRect;
        };
        droppableContainers: DroppableContainers;
        measuringConfiguration: DeepRequired<MeasuringConfiguration>;
        transform: Transform;
      }
      
      type DropAnimationFunction = (
        args: DropAnimationFunctionArguments
      ) => Promise<void> | void;
      

      Bug fixes

      • The <DragOverlay> now respects the measuringConfiguration specified for the dragOverlay and draggable properties when measuring the rects to animate to and from.
      • The <DragOverlay> component now supports rendering children while performing the drop animation. Previously, the drag overlay would be in a broken state when trying to pick up an item while a drop animation was in progress.

      Migration steps

      For consumers that were relying on the dragSourceOpacity property in their dropAnimation configuration:

      + import {defaultDropAnimationSideEffects} from '@dnd-kit/core';
      
      const dropAnimation = {
      - dragSourceOpacity: 0.5,
      + sideEffects: defaultDropAnimationSideEffects({
      +   styles : {
      +     active: {
      +       opacity: '0.5',
      +     },
      +   },
      +  ),
      };
      
    • #745 5f3c700 Thanks @clauderic! - The keyboard sensor now keeps track of the initial coordinates of the collision rect to provide a translate delta when move events are dispatched.

      This is a breaking change that may affect consumers that had created custom keyboard coordinate getters.

      Previously the keyboard sensor would measure the initial rect of the active node and store its top and left properties as its initial coordinates it would then compare all subsequent move coordinates to calculate the delta.

      This approach suffered from the following issues:

      • It didn't respect the measuring configuration defined on the <DndContext> for the draggable node
      • Some consumers re-render the active node after dragging begins, which would lead to stale measurements
      • An error had to be thrown if there was no active node during the activation phase of the keyboard sensor. This shouldn't be a concern of the keyboard sensor.
      • The currentCoordinates passed to the coordinate getter were often stale and not an accurate representation of the current position of the collision rect, which can be affected by a number of different variables, such as modifiers.
    • #755 33e6dd2 Thanks @clauderic! - The UniqueIdentifier type has been updated to now accept either string or number identifiers. As a result, the id property of useDraggable, useDroppable and useSortable and the items prop of <SortableContext> now all accept either string or number identifiers.

      Migration steps

      For consumers that are using TypeScript, import the UniqueIdentifier type to have strongly typed local state:

      + import type {UniqueIdentifier} from '@dnd-kit/core';
      
      function MyComponent() {
      -  const [items, setItems] = useState(['A', 'B', 'C']);
      +  const [items, setItems] = useState<UniqueIdentifier>(['A', 'B', 'C']);
      }
      

      Alternatively, consumers can cast or convert the id property to a string when reading the id property of interfaces such as Active, Over, DroppableContainer and DraggableNode.

      The draggableNodes object has also been converted to a map. Consumers that were reading from the draggableNodes property that is available on the public context of <DndContext> should follow these migration steps:

      - draggableNodes[someId];
      + draggableNodes.get(someId);
      

    Minor Changes

    • #748 59ca82b Thanks @clauderic! - Automatic focus management and activator node refs.

      Introducing activator node refs

      Introducing the concept of activator node refs for useDraggable and useSortable. This allows @dnd-kit to handle common use-cases such as restoring focus on the activator node after dragging via the keyboard or only allowing the activator node to instantiate the keyboard sensor.

      Consumers of useDraggable and useSortable may now optionally set the activator node ref on the element that receives listeners:

      import {useDraggable} from '@dnd-kit/core';
      
      function Draggable(props) {
        const {
          listeners,
          setNodeRef,
      +   setActivatorNodeRef,
        } = useDraggable({id: props.id});
      
        return (
          <div ref={setNodeRef}>
            Draggable element
            <button
              {...listeners}
      +       ref={setActivatorNodeRef}
            >
              :: Drag Handle
            </button>
          </div>
        )
      }
      

      It's common for the activator element (the element that receives the sensor listeners) to differ from the draggable node. When this happens, @dnd-kit has no reliable way to get a reference to the activator node after dragging ends, as the original event.target that instantiated the sensor may no longer be mounted in the DOM or associated with the draggable node that was previously active.

      Automatically restoring focus

      Focus management is now automatically handled by @dnd-kit. When the activator event is a Keyboard event, @dnd-kit will now attempt to automatically restore focus back to the first focusable node of the activator node or draggable node.

      If no activator node is specified via the setActivatorNodeRef setter function of useDraggble and useSortable, @dnd-kit will automatically restore focus on the first focusable node of the draggable node set via the setNodeRef setter function of useDraggable and useSortable.

      If you were previously managing focus manually and would like to opt-out of automatic focus management, use the newly introduced restoreFocus property of the accessibility prop of <DndContext>:

      <DndContext
        accessibility={{
      +   restoreFocus: false
        }}
      
    • #751 a52fba1 Thanks @clauderic! - Added the aria-disabled attribute to the attribtues object returned by useDraggable and useSortable. The value of the aria-disabled attribute is populated based on whether or not the disabled argument is passed to useDraggble or useSortable.

    • #741 40707ce Thanks @clauderic! - The auto scroller now keeps track of the drag direction to infer scroll intent. By default, auto-scrolling will now be disabled for a given direction if dragging in that direction hasn't occurred yet. This prevents accidental auto-scrolling when picking up a draggable item that is near the scroll boundary threshold.

    • #660 a41e5b8 Thanks @clauderic! - Fixed a bug with the delta property returned in onDragMove, onDragOver, onDragEnd and onDragCancel. The delta property represents the transform delta since dragging was initiated, along with the scroll delta. However, due to an oversight, the delta property was actually returning the transform delta and the current scroll offsets rather than the scroll delta.

      This same change has been made to the scrollAdjustedTranslate property that is exposed to sensors.

    • #750 bf30718 Thanks @clauderic! - The useDndMonitor() hook has been refactored to be synchronously invoked at the same time as the events dispatched by <DndContext> (such as onDragStart, onDragOver, onDragEnd).

      The new refactor uses the subscribe/notify pattern and no longer causes re-renders in consuming components of useDndMonitor() when events are dispatched.

    • #660 a41e5b8 Thanks @clauderic! - The activeNodeRect and containerNodeRect are now observed by a ResizeObserver in case they resize while dragging.

    • #660 a41e5b8 Thanks @clauderic! - Improved useDraggable usage without <DragOverlay>:

      • The active draggable now scrolls with the page even if there is no <DragOverlay> used.
      • Fixed issues when re-ordering the active draggable node in the DOM while dragging.
    • #660 77e3d44 Thanks @clauderic! - Fixed an issue with useDroppable hook needlessly dispatching SetDroppableDisabled actions even if the disabled property had not changed since registering the droppable.

    • #749 188a450 Thanks @clauderic! - The onDragStart, onDragMove, onDragOver, onDragEnd and onDragCancel events of <DndContext> and useDndMonitor now expose the activatorEvent event that instantiated the activated sensor.

    • #733 035021a Thanks @clauderic! - The KeyboardSensor now scrolls the focused activator draggable node into view if it is not within the viewport.

    • #733 035021a Thanks @clauderic! - By default, @dnd-kit now attempts to compensate for layout shifts that happen right after the onDragStart event is dispatched by scrolling the first scrollable ancestor of the active draggable node.

      The autoScroll prop of <DndContext> now optionally accepts a layoutShiftCompensation property to control this new behavior:

      interface AutoScrollOptions {
        acceleration?: number;
        activator?: AutoScrollActivator;
        canScroll?: CanScroll;
        enabled?: boolean;
        interval?: number;
      + layoutShiftCompensation?: boolean | {x: boolean, y: boolean};
        order?: TraversalOrder;
        threshold?: {
          x: number;
          y: number;
        };
      }
      

      To enable/disable layout shift scroll compensation for a single scroll axis, pass in the following autoscroll configuration to <DndContext>:

      <DndContext
        autoScroll={{layoutShiftCompensation: {x: false, y: true}}}
      >
      

      To completely disable layout shift scroll compensation, pass in the following autoscroll configuration to <DndContext>:

      <DndContext
        autoScroll={{layoutShiftCompensation: false}}
      >
      
    • #672 10f6836 Thanks @clauderic! - The measureDroppableContainers method now properly respects the MeasuringStrategy defined on <DndContext /> and will not measure containers while measuring is disabled.

    • #656 c1b3b5a Thanks @clauderic! - Fixed an issue with collision detection using stale rects. The droppableRects property has been added to the CollisionDetection interface.

      All built-in collision detection algorithms have been updated to get the rect for a given droppable container from droppableRects rather than from the rect.current ref:

      - const rect = droppableContainers.get(id).rect.current;
      + const rect = droppableRects.get(id);
      

      The rect.current ref stored on DroppableContainers can be stale if measuring is scheduled but has not completed yet. Collision detection algorithms should use the droppableRects map instead to get the latest, most up-to-date measurement of a droppable container in order to avoid computing collisions against stale rects.

      This is not a breaking change. However, if you've forked any of the built-in collision detection algorithms or you've authored custom ones, we highly recommend you update your use-cases to avoid possibly computing collisions against stale rects.

    Patch Changes

    • #742 7161f70 Thanks @clauderic! - Fallback to initial rect measured for the active draggable node if it unmounts during initialization (after onDragStart is dispatched).

    • #749 5811986 Thanks @clauderic! - The Data and DataRef types are now exported by @dnd-kit/core.

    • #699 e302bd4 Thanks @JuAn-Kang! - Export DragOverlayProps for consumers.

    • 750d726 Thanks @clauderic! - Fixed a bug in the KeyboardSensor where it would not move the draggable on the horizontal axis if it could fully scroll to the new vertical coordinates, and would not move the draggable on the vertical axis if it could fully scroll to the new horizontal coordinates.

    • #660 e6e242c Thanks @clauderic! - The KeyboardSensor was updated to use scrollTo instead of scrollBy when it is able to fully scroll to the new coordinates returned by the coordinate getter function. This resolves issues that can happen with scrollBy when called in rapid succession.

    • Updated dependencies [59ca82b, 035021a]:

    Source code(tar.gz)
    Source code(zip)
  • @dnd-kit/[email protected](Mar 12, 2022)

  • @dnd-kit/[email protected](Mar 11, 2022)

  • @dnd-kit/[email protected](Mar 11, 2022)

  • @dnd-kit/[email protected](Jan 10, 2022)

    Minor Changes

    • #518 6310227 Thanks @clauderic! - Major internal refactor of measuring and collision detection.

      Summary of changes

      Previously, all collision detection algorithms were relative to the top and left points of the document. While this approach worked in most situations, it broke down in a number of different use-cases, such as fixed position droppable containers and trying to drag between containers that had different scroll positions.

      This new approach changes the frame of comparison to be relative to the viewport. This is a major breaking change, and will need to be released under a new major version bump.

      Breaking changes:

      • By default, @dnd-kit now ignores only the transforms applied to the draggable / droppable node itself, but considers all the transforms applied to its ancestors. This should provide the right balance of flexibility for most consumers.
        • Transforms applied to the droppable and draggable nodes are ignored by default, because the recommended approach for moving items on the screen is to use the transform property, which can interfere with the calculation of collisions.
        • Consumers can choose an alternate approach that does consider transforms for specific use-cases if needed by configuring the measuring prop of . Refer to the example.
      • Reduced the number of concepts related to measuring from ViewRect, LayoutRect to just a single concept of ClientRect.
        • The ClientRect interface no longer holds the offsetTop and offsetLeft properties. For most use-cases, you can replace offsetTop with top and offsetLeft with left.
        • Replaced the following exports from the @dnd-kit/core package with getClientRect:
          • getBoundingClientRect
          • getViewRect
          • getLayoutRect
          • getViewportLayoutRect
      • Removed translatedRect from the SensorContext interface. Replace usage with collisionRect.
      • Removed activeNodeClientRect on the DndContext interface. Replace with activeNodeRect.
    • 528c67e Thanks @clauderic! - Introduced the useLatestValue hook, which returns a ref that holds the latest value of a given argument. Optionally, the second argument can be used to customize the dependencies passed to the effect.

    Patch Changes

    • #561 02edd26 Thanks @clauderic! - - The useNodeRef hook's onChange argument now receives both the current node and the previous node that were attached to the ref.
      • The onChange argument is only called if the previous node differs from the current node
    Source code(tar.gz)
    Source code(zip)
  • @dnd-kit/[email protected](Jan 10, 2022)

    Major Changes

    • #518 6310227 Thanks @clauderic! - Major internal refactor of measuring and collision detection.

      Summary of changes

      Previously, all collision detection algorithms were relative to the top and left points of the document. While this approach worked in most situations, it broke down in a number of different use-cases, such as fixed position droppable containers and trying to drag between containers that had different scroll positions.

      This new approach changes the frame of comparison to be relative to the viewport. This is a major breaking change, and will need to be released under a new major version bump.

      Breaking changes:

      • By default, @dnd-kit now ignores only the transforms applied to the draggable / droppable node itself, but considers all the transforms applied to its ancestors. This should provide the right balance of flexibility for most consumers.
        • Transforms applied to the droppable and draggable nodes are ignored by default, because the recommended approach for moving items on the screen is to use the transform property, which can interfere with the calculation of collisions.
        • Consumers can choose an alternate approach that does consider transforms for specific use-cases if needed by configuring the measuring prop of . Refer to the example.
      • Reduced the number of concepts related to measuring from ViewRect, LayoutRect to just a single concept of ClientRect.
        • The ClientRect interface no longer holds the offsetTop and offsetLeft properties. For most use-cases, you can replace offsetTop with top and offsetLeft with left.
        • Replaced the following exports from the @dnd-kit/core package with getClientRect:
          • getBoundingClientRect
          • getViewRect
          • getLayoutRect
          • getViewportLayoutRect
      • Removed translatedRect from the SensorContext interface. Replace usage with collisionRect.
      • Removed activeNodeClientRect on the DndContext interface. Replace with activeNodeRect.
    • #569 e7ac3d4 Thanks @clauderic! - Separated context into public and internal context providers. Certain properties that used to be available on the public DndContextDescriptor interface have been moved to the internal context provider and are no longer exposed to consumers:

      interface DndContextDescriptor {
      -  dispatch: React.Dispatch<Actions>;
      -  activators: SyntheticListeners;
      -  ariaDescribedById: {
      -    draggable: UniqueIdentifier;
      -  };
      }
      

      Having two distinct context providers will allow to keep certain internals such as dispatch hidden from consumers.

      It also serves as an optimization until context selectors are implemented in React, properties that change often, such as the droppable containers and droppable rects, the transform value and array of collisions should be stored on a different context provider to limit un-necessary re-renders in useDraggable, useDroppable and useSortable.

      The <InternalContext.Provider> is also reset to its default values within <DragOverlay>. This paves the way towards being able to seamlessly use components that use hooks such as useDraggable and useDroppable as children of <DragOverlay> without causing interference or namespace collisions.

      Consumers can still make calls to useDndContext() to get the active or over properties if they wish to re-render the component rendered within DragOverlay in response to user interaction, since those use the PublicContext

    Minor Changes

    • #558 f3ad20d Thanks @clauderic! - Refactor of the CollisionDetection interface to return an array of Collisions:

      +export interface Collision {
      +  id: UniqueIdentifier;
      +  data?: Record<string, any>;
      +}
      
      export type CollisionDetection = (args: {
        active: Active;
        collisionRect: ClientRect;
        droppableContainers: DroppableContainer[];
        pointerCoordinates: Coordinates | null;
      -}) => UniqueIdentifier;
      +}) => Collision[];
      

      This is a breaking change that requires all collision detection strategies to be updated to return an array of Collision rather than a single UniqueIdentifier

      The over property remains a single UniqueIdentifier, and is set to the first item in returned in the collisions array.

      Consumers can also access the collisions property which can be used to implement use-cases such as combining droppables in user-land.

      The onDragMove, onDragOver and onDragEnd callbacks are also updated to receive the collisions array property.

      Built-in collision detections such as rectIntersection, closestCenter, closestCorners and pointerWithin adhere to the CollisionDescriptor interface, which extends the Collision interface:

      export interface CollisionDescriptor extends Collision {
        data: {
          droppableContainer: DroppableContainer;
          value: number;
          [key: string]: any;
        };
      }
      

      Consumers can also access the array of collisions in components wrapped by <DndContext> via the useDndContext() hook:

      import {useDndContext} from '@dnd-kit/core';
      
      function MyComponent() {
        const {collisions} = useDndContext();
      }
      
    • #561 02edd26 Thanks @clauderic! - Droppable containers now observe the node they are attached to via setNodeRef using ResizeObserver while dragging.

      This behaviour can be configured using the newly introduced resizeObserverConfig property.

      interface ResizeObserverConfig {
        /** Whether the ResizeObserver should be disabled entirely */
        disabled?: boolean;
        /** Resize events may affect the layout and position of other droppable containers.
         * Specify an array of `UniqueIdentifier` of droppable containers that should also be re-measured
         * when this droppable container resizes. Specifying an empty array re-measures all droppable containers.
         */
        updateMeasurementsFor?: UniqueIdentifier[];
        /** Represents the debounce timeout between when resize events are observed and when elements are re-measured */
        timeout?: number;
      }
      

      By default, only the current droppable is scheduled to be re-measured when a resize event is observed. However, this may not be suitable for all use-cases. When an element resizes, it can affect the layout and position of other elements, such that it may be necessary to re-measure other droppable nodes in response to that single resize event. The recomputeIds property can be used to specify which droppable ids should be re-measured in response to resize events being observed.

      For example, the useSortable preset re-computes the measurements of all sortable elements after the element that resizes, so long as they are within the same SortableContext as the element that resizes, since it's highly likely that their layout will also shift.

      Specifying an empty array for recomputeIds forces all droppable containers to be re-measured.

      For consumers that were relyings on the internals of DndContext using useDndContext(), the willRecomputeLayouts property has been renamed to measuringScheduled, and the recomputeLayouts method has been renamed to measureDroppableContainers, and now optionally accepts an array of droppable UniqueIdentifier that should be scheduled to be re-measured.

    • #570 1ade2f3 Thanks @clauderic! - Use transition for the active draggable node when keyboard sorting without a <DragOverlay />.

    Patch Changes

    Source code(tar.gz)
    Source code(zip)
  • @dnd-kit/[email protected](Jan 10, 2022)

    Minor Changes

    • #567 cd3adf3 Thanks @clauderic! - Update modifiers to use draggingNodeRect instead of activeNodeRect. Modifiers should be based on the rect of the node being dragged, whether it is the draggable node or drag overlay node.

    • #518 6310227 Thanks @clauderic! - Major internal refactor of measuring and collision detection.

      Summary of changes

      Previously, all collision detection algorithms were relative to the top and left points of the document. While this approach worked in most situations, it broke down in a number of different use-cases, such as fixed position droppable containers and trying to drag between containers that had different scroll positions.

      This new approach changes the frame of comparison to be relative to the viewport. This is a major breaking change, and will need to be released under a new major version bump.

      Breaking changes:

      • By default, @dnd-kit now ignores only the transforms applied to the draggable / droppable node itself, but considers all the transforms applied to its ancestors. This should provide the right balance of flexibility for most consumers.
        • Transforms applied to the droppable and draggable nodes are ignored by default, because the recommended approach for moving items on the screen is to use the transform property, which can interfere with the calculation of collisions.
        • Consumers can choose an alternate approach that does consider transforms for specific use-cases if needed by configuring the measuring prop of . Refer to the example.
      • Reduced the number of concepts related to measuring from ViewRect, LayoutRect to just a single concept of ClientRect.
        • The ClientRect interface no longer holds the offsetTop and offsetLeft properties. For most use-cases, you can replace offsetTop with top and offsetLeft with left.
        • Replaced the following exports from the @dnd-kit/core package with getClientRect:
          • getBoundingClientRect
          • getViewRect
          • getLayoutRect
          • getViewportLayoutRect
      • Removed translatedRect from the SensorContext interface. Replace usage with collisionRect.
      • Removed activeNodeClientRect on the DndContext interface. Replace with activeNodeRect.

    Patch Changes

    Source code(tar.gz)
    Source code(zip)
  • @dnd-kit/[email protected](Jan 10, 2022)

  • @dnd-kit/[email protected](Jan 10, 2022)

    Major Changes

    • #558 f3ad20d Thanks @clauderic! - Refactor of the CollisionDetection interface to return an array of Collisions:

      +export interface Collision {
      +  id: UniqueIdentifier;
      +  data?: Record<string, any>;
      +}
      
      export type CollisionDetection = (args: {
        active: Active;
        collisionRect: ClientRect;
        droppableContainers: DroppableContainer[];
        pointerCoordinates: Coordinates | null;
      -}) => UniqueIdentifier;
      +}) => Collision[];
      

      This is a breaking change that requires all collision detection strategies to be updated to return an array of Collision rather than a single UniqueIdentifier

      The over property remains a single UniqueIdentifier, and is set to the first item in returned in the collisions array.

      Consumers can also access the collisions property which can be used to implement use-cases such as combining droppables in user-land.

      The onDragMove, onDragOver and onDragEnd callbacks are also updated to receive the collisions array property.

      Built-in collision detections such as rectIntersection, closestCenter, closestCorners and pointerWithin adhere to the CollisionDescriptor interface, which extends the Collision interface:

      export interface CollisionDescriptor extends Collision {
        data: {
          droppableContainer: DroppableContainer;
          value: number;
          [key: string]: any;
        };
      }
      

      Consumers can also access the array of collisions in components wrapped by <DndContext> via the useDndContext() hook:

      import {useDndContext} from '@dnd-kit/core';
      
      function MyComponent() {
        const {collisions} = useDndContext();
      }
      
    • #561 02edd26 Thanks @clauderic! - Droppable containers now observe the node they are attached to via setNodeRef using ResizeObserver while dragging.

      This behaviour can be configured using the newly introduced resizeObserverConfig property.

      interface ResizeObserverConfig {
        /** Whether the ResizeObserver should be disabled entirely */
        disabled?: boolean;
        /** Resize events may affect the layout and position of other droppable containers.
         * Specify an array of `UniqueIdentifier` of droppable containers that should also be re-measured
         * when this droppable container resizes. Specifying an empty array re-measures all droppable containers.
         */
        updateMeasurementsFor?: UniqueIdentifier[];
        /** Represents the debounce timeout between when resize events are observed and when elements are re-measured */
        timeout?: number;
      }
      

      By default, only the current droppable is scheduled to be re-measured when a resize event is observed. However, this may not be suitable for all use-cases. When an element resizes, it can affect the layout and position of other elements, such that it may be necessary to re-measure other droppable nodes in response to that single resize event. The recomputeIds property can be used to specify which droppable ids should be re-measured in response to resize events being observed.

      For example, the useSortable preset re-computes the measurements of all sortable elements after the element that resizes, so long as they are within the same SortableContext as the element that resizes, since it's highly likely that their layout will also shift.

      Specifying an empty array for recomputeIds forces all droppable containers to be re-measured.

      For consumers that were relyings on the internals of DndContext using useDndContext(), the willRecomputeLayouts property has been renamed to measuringScheduled, and the recomputeLayouts method has been renamed to measureDroppableContainers, and now optionally accepts an array of droppable UniqueIdentifier that should be scheduled to be re-measured.

    • #518 6310227 Thanks @clauderic! - Major internal refactor of measuring and collision detection.

      Summary of changes

      Previously, all collision detection algorithms were relative to the top and left points of the document. While this approach worked in most situations, it broke down in a number of different use-cases, such as fixed position droppable containers and trying to drag between containers that had different scroll positions.

      This new approach changes the frame of comparison to be relative to the viewport. This is a major breaking change, and will need to be released under a new major version bump.

      Breaking changes:

      • By default, @dnd-kit now ignores only the transforms applied to the draggable / droppable node itself, but considers all the transforms applied to its ancestors. This should provide the right balance of flexibility for most consumers.
        • Transforms applied to the droppable and draggable nodes are ignored by default, because the recommended approach for moving items on the screen is to use the transform property, which can interfere with the calculation of collisions.
        • Consumers can choose an alternate approach that does consider transforms for specific use-cases if needed by configuring the measuring prop of . Refer to the example.
      • Reduced the number of concepts related to measuring from ViewRect, LayoutRect to just a single concept of ClientRect.
        • The ClientRect interface no longer holds the offsetTop and offsetLeft properties. For most use-cases, you can replace offsetTop with top and offsetLeft with left.
        • Replaced the following exports from the @dnd-kit/core package with getClientRect:
          • getBoundingClientRect
          • getViewRect
          • getLayoutRect
          • getViewportLayoutRect
      • Removed translatedRect from the SensorContext interface. Replace usage with collisionRect.
      • Removed activeNodeClientRect on the DndContext interface. Replace with activeNodeRect.
    • #569 e7ac3d4 Thanks @clauderic! - Separated context into public and internal context providers. Certain properties that used to be available on the public DndContextDescriptor interface have been moved to the internal context provider and are no longer exposed to consumers:

      interface DndContextDescriptor {
      -  dispatch: React.Dispatch<Actions>;
      -  activators: SyntheticListeners;
      -  ariaDescribedById: {
      -    draggable: UniqueIdentifier;
      -  };
      }
      

      Having two distinct context providers will allow to keep certain internals such as dispatch hidden from consumers.

      It also serves as an optimization until context selectors are implemented in React, properties that change often, such as the droppable containers and droppable rects, the transform value and array of collisions should be stored on a different context provider to limit un-necessary re-renders in useDraggable, useDroppable and useSortable.

      The <InternalContext.Provider> is also reset to its default values within <DragOverlay>. This paves the way towards being able to seamlessly use components that use hooks such as useDraggable and useDroppable as children of <DragOverlay> without causing interference or namespace collisions.

      Consumers can still make calls to useDndContext() to get the active or over properties if they wish to re-render the component rendered within DragOverlay in response to user interaction, since those use the PublicContext

    Minor Changes

    • #556 c6c67cb Thanks @avgrad! - - Added pointer coordinates to collision detection
      • Added pointerWithin collision algorithm

    Patch Changes

    Source code(tar.gz)
    Source code(zip)
  • @dnd-kit/[email protected](Dec 14, 2021)

  • @dnd-kit/[email protected](Nov 22, 2021)

    Patch Changes

    • #509 1c6369e Thanks @clauderic! - Helpers have been updated to support rendering in foreign window contexts (via ReactDOM.render or ReactDOM.createPortal).

      For example, checking if an element is an instance of an HTMLElement is normally done like so:

      if (element instanceof HTMLElement)
      

      However, when rendering in a different window, this can return false even if the element is indeed an HTMLElement, because this code is equivalent to:

      if (element instanceof window.HTMLElement)
      

      And in this case, the window of the element is different from the main execution context window, because we are rendering via a portal into another window.

      This can be solved by finding the local window of the element:

      const elementWindow = element.ownerDocument.defaultView;
      
      if (element instanceof elementWindow.HTMLElement)
      
    Source code(tar.gz)
    Source code(zip)
  • @dnd-kit/[email protected](Nov 22, 2021)

    Patch Changes

    • #509 1c6369e Thanks @clauderic! - Helpers have been updated to support rendering in foreign window contexts (via ReactDOM.render or ReactDOM.createPortal).

      For example, checking if an element is an instance of an HTMLElement is normally done like so:

      if (element instanceof HTMLElement)
      

      However, when rendering in a different window, this can return false even if the element is indeed an HTMLElement, because this code is equivalent to:

      if (element instanceof window.HTMLElement)
      

      And in this case, the window of the element is different from the main execution context window, because we are rendering via a portal into another window.

      This can be solved by finding the local window of the element:

      const elementWindow = element.ownerDocument.defaultView;
      
      if (element instanceof elementWindow.HTMLElement)
      
    • Updated dependencies [1c6369e]:

    Source code(tar.gz)
    Source code(zip)
  • @dnd-kit/[email protected](Nov 18, 2021)

    Minor Changes

    • #486 d86529c Thanks @clauderic! - Improvements to better support swappable strategies:

      • Now exporting an arraySwap helper to be used instead of arrayMove onDragEnd.
      • Added the getNewIndex prop on useSortable. By default, useSortable assumes that items will be moved to their new index using arrayMove(), but this isn't always the case, especially when using strategies like rectSwappingStrategy. For those scenarios, consumers can now define custom logic that should be used to get the new index for an item on drop, for example, by computing the new order of items using arraySwap.

    Patch Changes

    Source code(tar.gz)
    Source code(zip)
  • @dnd-kit/[email protected](Nov 18, 2021)

  • @dnd-kit/[email protected](Oct 25, 2021)

  • @dnd-kit/[email protected](Sep 28, 2021)

  • @dnd-kit/[email protected](Sep 28, 2021)

    Major Changes

    • #427 f96cb5d Thanks @clauderic! - - Using transform-agnostic measurements for the DragOverlay node.

      • Renamed the overlayNode property to dragOverlay on the DndContextDescriptor interface.
    • 9cfac05 Thanks @clauderic! - Renamed the wasSorting property to wasDragging on the SortableContext and AnimateLayoutChanges interfaces.

    Minor Changes

    Patch Changes

    • #372 dbc9601 Thanks @clauderic! - Refactored DroppableContainers type from Record<UniqueIdentifier, DroppableContainer to a custom instance that extends the Map constructor and adds a few other methods such as toArray(), getEnabled() and getNodeFor(id).

      A unique key property was also added to the DraggableNode and DroppableContainer interfaces. This prevents potential race conditions in the mount and cleanup effects of useDraggable and useDroppable. It's possible for the clean-up effect to run after another React component using useDraggable or useDroppable mounts, which causes the newly mounted element to accidentally be un-registered.

    • #350 a13dbb6 Thanks @wmain! - Breaking change: The CollisionDetection interface has been refactored. It now receives an object that contains the active draggable node, along with the collisionRect and an array of droppableContainers.

      If you've built custom collision detection algorithms, you'll need to update them. Refer to this PR for examples of how to refactor collision detection functions to the new CollisionDetection interface.

      The sortableKeyboardCoordinates method has also been updated since it relies on the closestCorners collision detection algorithm. If you were using collision detection strategies in a custom sortableKeyboardCoordinates method, you'll need to update those as well.

    • 86d1f27 Thanks @clauderic! - Fixed a bug in the horizontalListSortingStrategy where it did not check if the currentRect was undefined.

    • e42a711 Thanks @clauderic! - Fixed a bug with the default layout animation function where it could return true initially even if the list had not been sorted yet. Now checking the wasDragging property to ensure no layout animation occurs if wasDragging is false.

    • #341 e02b737 Thanks @clauderic! - Return undefined instead of null for transition in useSortable

    • Updated dependencies [13be602, aede2cc, 05d6a78, a32a4c5, f96cb5d, dea715c, dbc9601, 46ec5e4, 7006464, 0e628bc, c447880, 2ba6dfe, 8d70540, 13be602, 422d083, c4b21b4, 5a41340, a13dbb6, e2ee0dc, 1fe9b5c, 1fe9b5c, 1f5ca27]:

    Source code(tar.gz)
    Source code(zip)
Owner
Claudéric Demers
Front End Development @Shopify
Claudéric Demers
🔀 Drag and drop for your React lists and tables. Accessible. Tiny.

react-movable See all the other examples and their source code! Installation yarn add react-movable Usage import * as React from 'react'; import { Li

Vojtech Miksu 1.3k Dec 30, 2022
Drag and drop page builder and CMS for React, Vue, Angular, and more

Drag and drop page builder and CMS for React, Vue, Angular, and more Use your code components and the stack of your choice. No more being pestered for

Builder.io 4.2k Jan 1, 2023
React drag and drop sort support flex layout and nested.

react-flex-dnd React drag and drop sort support flex layout and nested. This package using hooks, note that your React version is above 16.8 :) Why fl

lvshihao 7 Nov 14, 2022
ReactJS drag and drop functionality for mouse and touch devices

DragDropContainer and DropTarget Live demo: peterh32.github.io/react-drag-drop-container Features Very easy to implement and understand. Works on mous

Peter Hollingsworth 142 Sep 26, 2022
Drag and Drop for React

React DnD Drag and Drop for React. See the docs, tutorials and examples on the website: http://react-dnd.github.io/react-dnd/ See the changelog on the

React DnD 18.7k Jan 7, 2023
Drag and Drop for React

React DnD Drag and Drop for React. See the docs, tutorials and examples on the website: http://react-dnd.github.io/react-dnd/ See the changelog on the

React DnD 18.7k Jan 6, 2023
Drag and Drop for React

Drag and Drop for React

React DnD 18.7k Jan 4, 2023
Light React Drag & Drop files and images library styled by styled-components

Light React Drag & Drop files and images library styled by styled-components

null 143 Dec 28, 2022
React Drag and Drop file input

React Drag and Drop file input

Tran Anh Tuat 45 Dec 30, 2022
React drag and drop framework with inbuilt virtualizing scrollbars.

About us This library was made by Forecast - powered by AI, Forecast is supporting your work process with a complete Resource & Project Management pla

Forecast 51 Sep 21, 2022
Drag and Drop library for React.

react-tiny-dnd Drag and Drop library for React. Demo Install via npm npm install react-tiny-dnd or yarn add react-tiny-dnd Features Vertical lists Eas

Rafael Hovhannisyan 27 Nov 27, 2022
Creating an app using Drag and Drop with React without libraries 🤏

Creating an app using Drag and Drop with React without libraries ?? ! This time, we are going to implement the functionality to do a Drag & Drop with

Franklin Martinez 5 Sep 23, 2022
:ok_hand: Drag and drop so simple it hurts

Drag and drop so simple it hurts Official React wrapper for dragula. Demo Try out the demo! Install You can get it on npm. npm install react-dragula -

Nicolás Bevacqua 976 Nov 26, 2022
A directive based drag and drop container for solid-js

A directive based drag and drop container for solid-js

Isaac Hagoel 52 Dec 8, 2022
🦋 Component for building file fields - from basic file inputs to drag and drop image galleries.

?? react-butterfiles A small component for building file upload fields of any type, for example a simple file upload button or an image gallery field

Adrian Smijulj 45 Aug 26, 2022
Simple HTML5 drag-drop zone with React.js.

react-dropzone Simple React hook to create a HTML5-compliant drag'n'drop zone for files. Documentation and examples at https://react-dropzone.js.org.

null 9.4k Jan 2, 2023
example how to use react-dropzone for drag 'n drop uploader

Getting Started with Create React App This project was bootstrapped with Create React App. Available Scripts In the project directory, you can run: np

Hendra_Adri 1 Nov 5, 2021
Taskboard with drag'n drop feature. Built w/ React, TypeScript

Drag & Drop Taskboard A taskboard application with drag and drop feature. Live demo is here. Tech Stack Language: TypeScript UI-Components: Ant Design

Onur Önder 37 Dec 16, 2022
"Drag to resize" (sizing) as React Component.

react-drag-sizing "Drag to resize" (sizing) as React Component Rewritten with TS & React-hooks Polyfill workaround with React < 16.8 Support both mous

Fritz Lin 13 Nov 7, 2022