├── .gitbook
└── assets
│ ├── axis-aligned-rectangle.png
│ ├── closest-center-1-.png
│ ├── closest-center-2-.png
│ ├── closest-center-kanban.png
│ ├── closest-center.png
│ ├── closest-corners-kanban.png
│ ├── closest-corners.png
│ ├── concepts-illustration (1).svg
│ ├── concepts-illustration-large.svg
│ ├── concepts-illustration.svg
│ ├── custom-collision-detection-intersection.png
│ ├── custom-collision-detection.png
│ ├── draggable-large.svg
│ ├── draggable.png
│ ├── draggable.svg
│ ├── dragoverlay (1).png
│ ├── dragoverlay.png
│ ├── droppable-1-.png
│ ├── droppable-large.svg
│ ├── droppable.png
│ ├── droppable.svg
│ ├── example.png
│ ├── multiple-containers.png
│ ├── rect-intersection-1-.png
│ ├── rect-intersection.png
│ ├── robot-illustration-concepts.svg
│ ├── sortable-1-.png
│ ├── sortable-multiple-containers-empty-column-1-.png
│ ├── sortable-multiple-containers-empty-column.png
│ ├── sortable-multiple-containers-example.png
│ ├── sortable-multiple-containers.png
│ ├── sortable.png
│ ├── usesortable-1-.png
│ ├── usesortable-3-.png
│ └── usesortable.png
├── README.md
├── SUMMARY.md
├── api-documentation
├── constraints.md
├── context-provider
│ ├── README.md
│ ├── collision-detection-algorithms.md
│ ├── use-dnd-monitor.md
│ └── usedndcontext.md
├── draggable
│ ├── README.md
│ ├── clone.md
│ ├── drag-overlay.md
│ └── usedraggable.md
├── droppable
│ ├── README.md
│ └── usedroppable.md
├── modifiers.md
└── sensors
│ ├── README.md
│ ├── keyboard.md
│ ├── mouse.md
│ ├── pointer.md
│ └── touch.md
├── concepts
├── context-provider.md
├── draggable
│ ├── README.md
│ ├── clone.md
│ └── usedraggable.md
├── droppable
│ ├── README.md
│ └── usedroppable.md
└── sensors
│ ├── README.md
│ ├── keyboard.md
│ ├── mouse.md
│ └── touch.md
├── guides
├── accessibility.md
├── getting-started.md
└── installation.md
├── introduction
├── getting-started.md
└── installation.md
└── presets
├── sortable.md
└── sortable
├── README.md
├── sortable-context.md
└── usesortable.md
/.gitbook/assets/axis-aligned-rectangle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dnd-kit/docs/2449bcf9b0e9a727d16573880b0253cbfa777d4f/.gitbook/assets/axis-aligned-rectangle.png
--------------------------------------------------------------------------------
/.gitbook/assets/closest-center-1-.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dnd-kit/docs/2449bcf9b0e9a727d16573880b0253cbfa777d4f/.gitbook/assets/closest-center-1-.png
--------------------------------------------------------------------------------
/.gitbook/assets/closest-center-2-.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dnd-kit/docs/2449bcf9b0e9a727d16573880b0253cbfa777d4f/.gitbook/assets/closest-center-2-.png
--------------------------------------------------------------------------------
/.gitbook/assets/closest-center-kanban.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dnd-kit/docs/2449bcf9b0e9a727d16573880b0253cbfa777d4f/.gitbook/assets/closest-center-kanban.png
--------------------------------------------------------------------------------
/.gitbook/assets/closest-center.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dnd-kit/docs/2449bcf9b0e9a727d16573880b0253cbfa777d4f/.gitbook/assets/closest-center.png
--------------------------------------------------------------------------------
/.gitbook/assets/closest-corners-kanban.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dnd-kit/docs/2449bcf9b0e9a727d16573880b0253cbfa777d4f/.gitbook/assets/closest-corners-kanban.png
--------------------------------------------------------------------------------
/.gitbook/assets/closest-corners.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dnd-kit/docs/2449bcf9b0e9a727d16573880b0253cbfa777d4f/.gitbook/assets/closest-corners.png
--------------------------------------------------------------------------------
/.gitbook/assets/custom-collision-detection-intersection.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dnd-kit/docs/2449bcf9b0e9a727d16573880b0253cbfa777d4f/.gitbook/assets/custom-collision-detection-intersection.png
--------------------------------------------------------------------------------
/.gitbook/assets/custom-collision-detection.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dnd-kit/docs/2449bcf9b0e9a727d16573880b0253cbfa777d4f/.gitbook/assets/custom-collision-detection.png
--------------------------------------------------------------------------------
/.gitbook/assets/draggable-large.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/.gitbook/assets/draggable.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dnd-kit/docs/2449bcf9b0e9a727d16573880b0253cbfa777d4f/.gitbook/assets/draggable.png
--------------------------------------------------------------------------------
/.gitbook/assets/draggable.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/.gitbook/assets/dragoverlay (1).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dnd-kit/docs/2449bcf9b0e9a727d16573880b0253cbfa777d4f/.gitbook/assets/dragoverlay (1).png
--------------------------------------------------------------------------------
/.gitbook/assets/dragoverlay.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dnd-kit/docs/2449bcf9b0e9a727d16573880b0253cbfa777d4f/.gitbook/assets/dragoverlay.png
--------------------------------------------------------------------------------
/.gitbook/assets/droppable-1-.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dnd-kit/docs/2449bcf9b0e9a727d16573880b0253cbfa777d4f/.gitbook/assets/droppable-1-.png
--------------------------------------------------------------------------------
/.gitbook/assets/droppable-large.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/.gitbook/assets/droppable.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dnd-kit/docs/2449bcf9b0e9a727d16573880b0253cbfa777d4f/.gitbook/assets/droppable.png
--------------------------------------------------------------------------------
/.gitbook/assets/droppable.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/.gitbook/assets/example.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dnd-kit/docs/2449bcf9b0e9a727d16573880b0253cbfa777d4f/.gitbook/assets/example.png
--------------------------------------------------------------------------------
/.gitbook/assets/multiple-containers.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dnd-kit/docs/2449bcf9b0e9a727d16573880b0253cbfa777d4f/.gitbook/assets/multiple-containers.png
--------------------------------------------------------------------------------
/.gitbook/assets/rect-intersection-1-.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dnd-kit/docs/2449bcf9b0e9a727d16573880b0253cbfa777d4f/.gitbook/assets/rect-intersection-1-.png
--------------------------------------------------------------------------------
/.gitbook/assets/rect-intersection.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dnd-kit/docs/2449bcf9b0e9a727d16573880b0253cbfa777d4f/.gitbook/assets/rect-intersection.png
--------------------------------------------------------------------------------
/.gitbook/assets/sortable-1-.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dnd-kit/docs/2449bcf9b0e9a727d16573880b0253cbfa777d4f/.gitbook/assets/sortable-1-.png
--------------------------------------------------------------------------------
/.gitbook/assets/sortable-multiple-containers-empty-column-1-.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dnd-kit/docs/2449bcf9b0e9a727d16573880b0253cbfa777d4f/.gitbook/assets/sortable-multiple-containers-empty-column-1-.png
--------------------------------------------------------------------------------
/.gitbook/assets/sortable-multiple-containers-empty-column.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dnd-kit/docs/2449bcf9b0e9a727d16573880b0253cbfa777d4f/.gitbook/assets/sortable-multiple-containers-empty-column.png
--------------------------------------------------------------------------------
/.gitbook/assets/sortable-multiple-containers-example.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dnd-kit/docs/2449bcf9b0e9a727d16573880b0253cbfa777d4f/.gitbook/assets/sortable-multiple-containers-example.png
--------------------------------------------------------------------------------
/.gitbook/assets/sortable-multiple-containers.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dnd-kit/docs/2449bcf9b0e9a727d16573880b0253cbfa777d4f/.gitbook/assets/sortable-multiple-containers.png
--------------------------------------------------------------------------------
/.gitbook/assets/sortable.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dnd-kit/docs/2449bcf9b0e9a727d16573880b0253cbfa777d4f/.gitbook/assets/sortable.png
--------------------------------------------------------------------------------
/.gitbook/assets/usesortable-1-.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dnd-kit/docs/2449bcf9b0e9a727d16573880b0253cbfa777d4f/.gitbook/assets/usesortable-1-.png
--------------------------------------------------------------------------------
/.gitbook/assets/usesortable-3-.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dnd-kit/docs/2449bcf9b0e9a727d16573880b0253cbfa777d4f/.gitbook/assets/usesortable-3-.png
--------------------------------------------------------------------------------
/.gitbook/assets/usesortable.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dnd-kit/docs/2449bcf9b0e9a727d16573880b0253cbfa777d4f/.gitbook/assets/usesortable.png
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | description: >-
3 | @dnd-kit – A lightweight, modular, performant, accessible and extensible drag
4 | & drop toolkit for React.
5 | ---
6 |
7 | # Overview
8 |
9 | * **Feature packed:** customizable collision detection algorithms, multiple activators, draggable overlay, drag handles, auto-scrolling, constraints, and so much more.
10 | * **Built for React:** exposes hooks such as [`useDraggable`](api-documentation/draggable/usedraggable.md) and [`useDroppable`](api-documentation/droppable/usedroppable.md), and won't require you to re-architect your app or create additional wrapper DOM nodes.
11 | * **Supports a wide range of use cases:** lists, grids, multiple containers, nested contexts, variable sized items, virtualized lists, 2D Games, and more.
12 | * **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.
13 | * **Built-in support for multiple input methods:** Pointer, mouse, touch and keyboard sensors.
14 | * **Fully customizable & extensible:** Customize every detail – animations, transitions, behaviours, styles. Build your own [sensors](api-documentation/sensors/), [collision detection algorithms](api-documentation/context-provider/collision-detection-algorithms.md), customize key bindings and so much more.
15 | * **Accessibility:** Keyboard support, sensible default aria attributes, customizable screen reader instructions and live regions built-in.
16 | * **Performance:** It was built with performance in mind in order to support silky smooth animations.
17 | * **Presets:** Need to build a sortable interface? Check out [`@dnd-kit/sortable`](presets/sortable/), which is a thin layer built on top of `@dnd-kit/core`. More presets coming in the future.
18 |
19 | 
20 |
21 | The core library of **dnd kit** exposes two main concepts:
22 |
23 | * [Draggable elements](api-documentation/draggable/)
24 | * [Droppable areas](api-documentation/droppable/)
25 |
26 | Augment your existing components using the [`useDraggable`](api-documentation/draggable/usedraggable.md) and [`useDroppable`](api-documentation/droppable/usedroppable.md) hooks, or combine both to create components that can both be dragged and dropped over.
27 |
28 | Handle events and customize the behaviour of your draggable elements and droppable areas using the [``](api-documentation/context-provider/) provider. Configure [sensors](api-documentation/sensors/) to handle different input methods.
29 |
30 | Use the [``](api-documentation/draggable/drag-overlay.md) component to render a draggable overlay that is removed from the normal document flow and is positioned relative to the viewport.
31 |
32 | Check out our quick start guide to learn how get started:
33 |
34 | {% content-ref url="introduction/getting-started.md" %}
35 | [getting-started.md](introduction/getting-started.md)
36 | {% endcontent-ref %}
37 |
38 | ### Extensibility
39 |
40 | Extensibility is at the core of **dnd kit**. It was 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`.
41 |
42 | A prime example of the level of extensibility of **dnd kit** is the[ Sortable preset](presets/sortable/), which is built using the extension points that are exposed by `@dnd-kit/core`.
43 |
44 | The primary extension points are:
45 |
46 | * [Sensors](api-documentation/sensors/)
47 | * [Modifiers](api-documentation/modifiers.md)
48 | * [Custom collision detection algorithms](api-documentation/context-provider/collision-detection-algorithms.md#custom-collision-detection-strategies)
49 |
50 | ### Accessibility
51 |
52 | Building drag and drop interfaces that are accessible to everyone isn't easy, and requires thoughtful consideration.
53 |
54 | The `@dnd-kit/core` library provides a number of starting points to help you make your drag and drop interfaces accessible:
55 |
56 | * [Keyboard support ](api-documentation/sensors/keyboard.md)out of the box
57 | * [Customizable screen reader instructions](guides/accessibility.md#screen-reader-instructions) for how to interact with draggable items
58 | * [Customizable live region updates](guides/accessibility.md#screen-reader-announcements-using-live-regions) to provide screen reader announcements in real-time of what is currently happening with draggable and droppable elements.
59 | * [Sensible defaults for attributes](api-documentation/draggable/usedraggable.md#attributes) that should be passed to draggable elements
60 |
61 | Check out our Accessibility guide to learn more about how you can help make your drag and drop interface accessible for everyone:
62 |
63 | {% content-ref url="guides/accessibility.md" %}
64 | [accessibility.md](guides/accessibility.md)
65 | {% endcontent-ref %}
66 |
67 | ### Architecture
68 |
69 | Unlike many drag and drop libraries, **dnd kit** is **** intentionally **not** built on top of the [HTML5 Drag and drop API](https://developer.mozilla.org/en-US/docs/Web/API/HTML\_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. For most web applications, we believe the benefits outweigh the tradeoffs.
70 |
71 | 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.
72 |
73 | 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](https://github.com/react-dnd/react-dnd/) for a React library that's has a native HTML 5 Drag and drop backend.
74 |
75 | ### Performance
76 |
77 | #### **Minimizing DOM mutations**
78 |
79 | **dnd kit** lets you build drag and drop interfaces without having to mutate the DOM every time an item needs to shift position.
80 |
81 | This is possible because **dnd kit** lazily calculates and stores the initial positions and client rects 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`](presets/sortable/) library.
82 |
83 | 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`.
84 |
85 | #### Synthetic events
86 |
87 | Sensors use [SyntheticEvent listeners](https://reactjs.org/docs/events.html) for the activator events of all sensors, which leads to improved performance over manually adding event listeners to each individual draggable node.
88 |
--------------------------------------------------------------------------------
/SUMMARY.md:
--------------------------------------------------------------------------------
1 | # Table of contents
2 |
3 | * [Overview](README.md)
4 |
5 | ## Introduction
6 |
7 | * [Installation](introduction/installation.md)
8 | * [Quick start](introduction/getting-started.md)
9 |
10 | ## API Documentation
11 |
12 | * [DndContext](api-documentation/context-provider/README.md)
13 | * [Collision detection algorithms](api-documentation/context-provider/collision-detection-algorithms.md)
14 | * [useDndContext](api-documentation/context-provider/usedndcontext.md)
15 | * [useDndMonitor](api-documentation/context-provider/use-dnd-monitor.md)
16 | * [Droppable](api-documentation/droppable/README.md)
17 | * [useDroppable](api-documentation/droppable/usedroppable.md)
18 | * [Draggable](api-documentation/draggable/README.md)
19 | * [useDraggable](api-documentation/draggable/usedraggable.md)
20 | * [Drag Overlay](api-documentation/draggable/drag-overlay.md)
21 | * [Sensors](api-documentation/sensors/README.md)
22 | * [Pointer](api-documentation/sensors/pointer.md)
23 | * [Mouse](api-documentation/sensors/mouse.md)
24 | * [Touch](api-documentation/sensors/touch.md)
25 | * [Keyboard](api-documentation/sensors/keyboard.md)
26 | * [Modifiers](api-documentation/modifiers.md)
27 |
28 | ## Presets
29 |
30 | * [Sortable](presets/sortable/README.md)
31 | * [Sortable Context](presets/sortable/sortable-context.md)
32 | * [useSortable](presets/sortable/usesortable.md)
33 |
34 | ## Guides
35 |
36 | * [Accessibility](guides/accessibility.md)
37 |
38 |
--------------------------------------------------------------------------------
/api-documentation/constraints.md:
--------------------------------------------------------------------------------
1 | # Constraints
2 |
3 |
--------------------------------------------------------------------------------
/api-documentation/context-provider/README.md:
--------------------------------------------------------------------------------
1 | # DndContext
2 |
3 | ## Application structure
4 |
5 | ### Context provider
6 |
7 | In order for your your [Droppable](../droppable/) and [Draggable](../draggable/) components to interact with each other, you'll need to make sure that the part of your React tree that uses them is nested within a parent `` component. The `` provider makes use of the [React Context API](https://reactjs.org/docs/context.html) to share data between draggable and droppable components and hooks.
8 |
9 | > React context provides a way to pass data through the component tree without having to pass props down manually at every level.
10 |
11 | Therefore, components that use [`useDraggable`](../draggable/usedraggable.md), [`useDroppable`](../droppable/usedroppable.md) or [`DragOverlay`](../draggable/drag-overlay.md) will need to be nested within a `DndContext` provider.
12 |
13 | They don't need to be direct descendants, but, there does need to be a parent `` provider somewhere higher up in the tree.
14 |
15 | ```jsx
16 | import React from 'react';
17 | import {DndContext} from '@dnd-kit/core';
18 |
19 | function App() {
20 | return (
21 |
22 | {/* Components that use `useDraggable`, `useDroppable` */}
23 |
24 | );
25 | }
26 | ```
27 |
28 | ### Nesting
29 |
30 | You may also nest `` providers within other `` providers to achieve nested draggable/droppable interfaces that are independent of one another.
31 |
32 | ```jsx
33 | import React from 'react';
34 | import {DndContext} from '@dnd-kit/core';
35 |
36 | function App() {
37 | return (
38 |
39 | {/* Components that use `useDraggable`, `useDroppable` */}
40 |
41 | {/* ... */}
42 |
43 | {/* ... */}
44 |
45 |
46 |
47 | );
48 | }
49 | ```
50 |
51 | When nesting `DndContext` providers, keep in mind that the `useDroppable` and `useDraggable` hooks will only have access to the other draggable and droppable nodes within that context.
52 |
53 | If multiple `DndContext` providers are listening for the same event, events will be captured by the first `DndContext` that contains a [Sensor](../sensors/) that is activated by that event, similar to how [events bubble in the DOM](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Events#Event_bubbling_and_capture).
54 |
55 | ## Props
56 |
57 | ```typescript
58 | interface Props {
59 | announcements?: Announcements;
60 | autoScroll?: boolean;
61 | cancelDrop?: CancelDrop;
62 | children?: React.ReactNode;
63 | collisionDetection?: CollisionDetection;
64 | layoutMeasuring?: Partial;
65 | modifiers?: Modifiers;
66 | screenReaderInstructions?: ScreenReaderInstructions;
67 | sensors?: SensorDescriptor[];
68 | onDragStart?(event: DragStartEvent): void;
69 | onDragMove?(event: DragMoveEvent): void;
70 | onDragOver?(event: DragOverEvent): void;
71 | onDragEnd?(event: DragEndEvent): void;
72 | onDragCancel?(): void;
73 | }
74 | ```
75 |
76 | ### Event handlers
77 |
78 | As you can see from the list of props above, there are a number of different events emitted by `` that you can listen to and decide how to handle.
79 |
80 | The main events you can listen to are:
81 |
82 | #### `onDragStart`
83 |
84 | Fires when a drag event that meets the [activation constraints](../sensors/#concepts) for that [sensor ](../sensors/)happens, along with the unique identifier of the draggable element that was picked up.
85 |
86 | #### `onDragMove`
87 |
88 | Fires anytime as the [draggable](../draggable/) item is moved. Depending on the activated [sensor](../sensors/#activators), this could for example be as the [Pointer](../sensors/pointer.md) is moved or the [Keyboard](../sensors/keyboard.md) movement keys are pressed.
89 |
90 | #### `onDragOver`
91 |
92 | Fires when a [draggable](../draggable/) item is moved over a [droppable](../droppable/) container, along with the unique identifier of that droppable container.
93 |
94 | #### `onDragEnd`
95 |
96 | Fires after a draggable item is dropped.
97 |
98 | This event contains information about the active draggable `id` along with information on whether the draggable item was dropped `over`.
99 |
100 | If there are no [collisions detected](collision-detection-algorithms.md) when the draggable item is dropped, the `over` property will be `null`. If a collision is detected, the `over` property will contain the `id` of the droppable over which it was dropped.
101 |
102 | {% hint style="info" %}
103 | It's important to understand that the `onDragEnd` event **does not move** [**draggable**](../draggable/) **items into** [**droppable**](../droppable/) **containers.**
104 |
105 | Rather, it provides **information** about which draggable item was dropped and whether it was over a droppable container when it was dropped.
106 |
107 | It is up to the **consumer** of `DndContext` to decide what to do with that information and how to react to it, for example, by updating \(or not\) its internal state in response to the event so that the items are declaratively rendered in a different parent droppable.
108 | {% endhint %}
109 |
110 | #### `onDragCancel`
111 |
112 | Fires if a drag operation is cancelled, for example, if the user presses `escape` while dragging a draggable item.
113 |
114 | ### Accessibility
115 |
116 | For more details and best practices around accessibility of draggable and droppable components, read the accessibility section:
117 |
118 | {% page-ref page="../../guides/accessibility.md" %}
119 |
120 | #### Announcements
121 |
122 | Use the `announcements` prop to customize the screen reader announcements that are announced in the live region when draggable items are picked up, moved over droppable regions, and dropped.
123 |
124 | The default announcements are:
125 |
126 | ```javascript
127 | const defaultAnnouncements = {
128 | onDragStart(id) {
129 | return `Picked up draggable item ${id}.`;
130 | },
131 | onDragOver(id, overId) {
132 | if (overId) {
133 | return `Draggable item ${id} was moved over droppable area ${overId}.`;
134 | }
135 |
136 | return `Draggable item ${id} is no longer over a droppable area.`;
137 | },
138 | onDragEnd(id, overId) {
139 | if (overId) {
140 | return `Draggable item was dropped over droppable area ${overId}`;
141 | }
142 |
143 | return `Draggable item ${id} was dropped.`;
144 | },
145 | onDragCancel(id) {
146 | return `Dragging was cancelled. Draggable item ${id} was dropped.`;
147 | },
148 | }
149 | ```
150 |
151 | While these default announcements are sensible defaults that should cover most simple use cases, you know your application best, and we highly recommend that you customize these to provide a screen reader experience that is more tailored to the use case you are building.
152 |
153 | #### Screen reader instructions
154 |
155 | Use the `screenReaderInstructions` prop to customize the instructions that are read to screen readers when the focus is moved
156 |
157 | ### Autoscroll
158 |
159 | Use the optional `autoScroll` boolean prop to temporarily or permanently disable auto-scrolling for all sensors used within this `DndContext`.
160 |
161 | Auto-scrolling may also be disabled on an individual sensor basis using the static property `autoScrollEnabled` of the sensor. For example, the [Keyboard sensor](../sensors/keyboard.md) manages scrolling internally, and therefore has the static property `autoScrollEnabled` set to `false`.
162 |
163 | ### Collision detection
164 |
165 | Use the `collisionDetection` prop to customize the collision detection algorithm used to detect collisions between draggable nodes and droppable areas within the`DndContext` provider.
166 |
167 | The default collision detection algorithm is the [rectangle intersection](collision-detection-algorithms.md#rectangle-intersection) algorithm.
168 |
169 | The built-in collision detection algorithms are:
170 |
171 | * [Rectangle intersection](collision-detection-algorithms.md#rectangle-intersection)
172 | * [Closest center](collision-detection-algorithms.md#closest-center)
173 | * [Closest corners](collision-detection-algorithms.md#closest-corners)
174 |
175 | You may also build custom collision detection algorithms or compose existing ones.
176 |
177 | To learn more, read the collision detection guide:
178 |
179 | {% page-ref page="collision-detection-algorithms.md" %}
180 |
181 | ### Sensors
182 |
183 | Sensors are an abstraction to detect different input methods in order to initiate drag operations, respond to movement and end or cancel the operation.
184 |
185 | The default sensors used by `DndContext` are the [Pointer](../sensors/pointer.md) and [Keyboard](../sensors/keyboard.md) sensors.
186 |
187 | To learn how to customize sensors or how to pass different sensors to `DndContext`, read the Sensors guide:
188 |
189 | {% page-ref page="../sensors/" %}
190 |
191 | ### Modifiers
192 |
193 | Modifiers let you dynamically modify the movement coordinates that are detected by sensors. They can be used for a wide range of use cases, for example:
194 |
195 | * Restricting motion to a single axis
196 | * Restricting motion to the draggable node container's bounding rectangle
197 | * Restricting motion to the draggable node's scroll container bounding rectangle
198 | * Applying resistance or clamping the motion
199 |
200 | To learn more about how to use Modifiers, read the Modifiers guide:
201 |
202 | {% page-ref page="../modifiers.md" %}
203 |
204 | ### Layout measuring
205 |
206 | You can configure when and how often `DndContext` should measure its droppable elements by using the `layoutMeasuring` prop.
207 |
208 | The `frequency` argument controls how frequently layouts should be measured. By default, layout measuring is set to `optimized`, which only measures layouts based on the `strategy`.
209 |
210 | Specify one of the following strategies:
211 |
212 | * `LayoutMeasuringStrategy.WhileDragging`: Default behavior, only measure droppable elements right after dragging has begun.
213 |
214 | `LayoutMeasuringStrategy.BeforeDragging`: Measure droppable elements before dragging begins and right after it ends.
215 |
216 | * `LayoutMeasuringStrategy.Always`: Measure droppable elements before dragging begins, right after dragging has begun, and after it ends.
217 |
218 | Example usage:
219 |
220 | ```jsx
221 | import {DndContext, LayoutMeasuringStrategy} from '@dnd-kit/core';
222 |
223 |
224 | ```
225 |
226 |
--------------------------------------------------------------------------------
/api-documentation/context-provider/collision-detection-algorithms.md:
--------------------------------------------------------------------------------
1 | # Collision detection algorithms
2 |
3 | If you're familiar with how 2D games are built, you may have come across the notion of collision detection algorithms.
4 |
5 | One of the simpler forms of collision detection is between two rectangles that are axis aligned — meaning rectangles that are not rotated. This form of collision detection is generally referred to as [Axis-Aligned Bounding Box](https://developer.mozilla.org/en-US/docs/Games/Techniques/2D\_collision\_detection#Axis-Aligned\_Bounding\_Box) (AABB).
6 |
7 | The built-in collision detection algorithms assume a rectangular bounding box.
8 |
9 | > The bounding box of an element is the smallest possible rectangle (aligned with the axes of that element's user coordinate system) that entirely encloses it and its descendants.\
10 | > – Source: [MDN](https://developer.mozilla.org/en-US/docs/Glossary/bounding\_box)
11 |
12 | This means that even if the draggable or droppable nodes look round or triangular, their bounding boxes will still be rectangular:
13 |
14 | 
15 |
16 | If you'd like to use other shapes than rectangles for detecting collisions, build your own [custom collision detection algorithm](collision-detection-algorithms.md#custom-collision-detection-strategies).
17 |
18 | ## Rectangle intersection
19 |
20 | By default, [`DndContext`](./) uses the **rectangle intersection** collision detection algorithm.
21 |
22 | The algorithm works by ensuring there is no gap between any of the 4 sides of the rectangles. Any gap means a collision does not exist.
23 |
24 | This means that in order for a draggable item to be considered **over** a droppable area, there needs to be an intersection between both rectangles:
25 |
26 | 
27 |
28 | ## Closest center
29 |
30 | While the rectangle intersection algorithm is well suited for most drag and drop use cases, it can be unforgiving, since it requires both the draggable and droppable bounding rectangles to come into direct contact and intersect.
31 |
32 | For some use cases, such as [sortable](../../presets/sortable/) lists, using a more forgiving collision detection algorithm is recommended.
33 |
34 | As its name suggests, the closest center algorithm finds the droppable container who's center is closest to the center of the bounding rectangle of the active draggable item:
35 |
36 | 
37 |
38 | ## Closest corners
39 |
40 | Like to the closest center algorithm, the closest corner algorithm doesn't require the draggable and droppable rectangles to intersect.
41 |
42 | Rather, it measures the distance between all four corners of the active draggable item and the four corners of each droppable container to find the closest one.
43 |
44 | 
45 |
46 | The distance is measured from the top left corner of the draggable item to the top left corner of the droppable bounding rectangle, top right to top right, bottom left to bottom left, and bottom right to bottom right.
47 |
48 | ### **When should I use the closest corners algorithm instead of closest center?**
49 |
50 | In most cases, the **closest center** algorithm works well, and is generally the recommended default for sortable lists because it provides a more forgiving experience than the **rectangle intersection algorithm**.
51 |
52 | In general, the closest center and closest corners algorithms will yield the same results. However, when building interfaces where droppable containers are stacked on top of one another, for example, when building a Kanban, the closest center algorithm can sometimes return the underlaying droppable of the entire Kanban column rather than the droppable areas within that column.
53 |
54 | 
55 |
56 | In those situations, the **closest corners** algorithm is preferred and will yield results that are more aligned with what the human eye would predict:
57 |
58 | 
59 |
60 | ## Pointer within
61 |
62 | As its name suggests, the pointer within collision detection algorithm only registers collision when the pointer is contained within the bounding rectangle of other droppable containers.
63 |
64 | This collision detection algorithm is well suited for high precision drag and drop interfaces.
65 |
66 | {% hint style="info" %}
67 | As its name suggests, this collision detection algorithm **only works with pointer-based sensors**. For this reason, we suggest you use [composition of collision detection algorithms](collision-detection-algorithms.md#composition-of-existing-algorithms) if you intend to use the `pointerWithin` collision detection algorithm so that you can fall back to a different collision detection algorithm for the Keyboard sensor.
68 | {% endhint %}
69 |
70 | ## Custom collision detection algorithms
71 |
72 | In advanced use cases, you may want to build your own collision detection algorithms if the ones provided out of the box do not suit your use case.
73 |
74 | You can either write a new collision detection algorithm from scratch, or compose two or more existing collision detection algorithms.
75 |
76 | ### Composition of existing algorithms
77 |
78 | Sometimes, you don't need to build custom collision detection algorithms from scratch. Instead, you can compose existing collision algorithms to augment them.
79 |
80 | A common example of this is when using the `pointerWithin` collision detection algorithm. As its name suggest, this collision detection algorithm depends on pointer coordinates, and therefore does not work when using other sensors like the Keyboard sensor. It's also a very high precision collision detection algorithm, so it can sometimes be helpful to fall back to a more tolerant collision detection algorithm when the `pointerWithin` algorithm does not return any collisions.
81 |
82 | ```javascript
83 | import {pointerWithin, rectIntersection} from '@dnd-kit/core';
84 |
85 | function customCollisionDetectionAlgorithm(args) {
86 | // First, let's see if there are any collisions with the pointer
87 | const pointerCollisions = pointerWithin(args);
88 |
89 | // Collision detection algorithms return an array of collisions
90 | if (pointerCollisions.length > 0) {
91 | return pointerCollisions;
92 | }
93 |
94 | // If there are no collisions with the pointer, return rectangle intersections
95 | return rectIntersection(args);
96 | };
97 | ```
98 |
99 | Another example where composition of existing algorithms can be useful is if you want some of your droppable containers to have a different collision detection algorithm than the others.
100 |
101 | For instance, if you were building a sortable list that also supported moving items to a trash bin, you may want to compose both the `closestCenter` and `rectangleIntersection` collision detection algorithms.
102 |
103 | 
104 |
105 | 
106 |
107 | From an implementation perspective, the custom intersection algorithm described in the example above would look like:
108 |
109 | ```javascript
110 | import {closestCorners, rectIntersection} from '@dnd-kit/core';
111 |
112 | function customCollisionDetectionAlgorithm({
113 | droppableContainers,
114 | ...args,
115 | }) {
116 | // First, let's see if the `trash` droppable rect is intersecting
117 | const rectIntersectionCollisions = rectIntersection({
118 | ...args,
119 | droppableContainers: droppableContainers.filter(({id}) => id === 'trash')
120 | });
121 |
122 | // Collision detection algorithms return an array of collisions
123 | if (rectIntersectionCollisions.length > 0) {
124 | // The trash is intersecting, return early
125 | return rectIntersectionCollisions;
126 | }
127 |
128 | // Compute other collisions
129 | return closestCorners({
130 | ...args,
131 | droppableContainers: droppableContainers.filter(({id}) => id !== 'trash')
132 | });
133 | };
134 | ```
135 |
136 | ### Building custom collision detection algorithms
137 |
138 | For advanced use cases or to detect collision between non-rectangular or non-axis aligned shapes, you'll want to build your own collision detection algorithms.
139 |
140 | Here's an example to [detect collisions between circles](https://developer.mozilla.org/en-US/docs/Games/Techniques/2D\_collision\_detection#Circle\_Collision) instead of rectangles:
141 |
142 | ```javascript
143 | /**
144 | * Sort collisions in descending order (from greatest to smallest value)
145 | */
146 | export function sortCollisionsDesc(
147 | {data: {value: a}},
148 | {data: {value: b}}
149 | ) {
150 | return b - a;
151 | }
152 |
153 | function getCircleIntersection(entry, target) {
154 | // Abstracted the logic to calculate the radius for simplicity
155 | var circle1 = {radius: 20, x: entry.offsetLeft, y: entry.offsetTop};
156 | var circle2 = {radius: 12, x: target.offsetLeft, y: target.offsetTop};
157 |
158 | var dx = circle1.x - circle2.x;
159 | var dy = circle1.y - circle2.y;
160 | var distance = Math.sqrt(dx * dx + dy * dy);
161 |
162 | if (distance < circle1.radius + circle2.radius) {
163 | return distance;
164 | }
165 |
166 | return 0;
167 | }
168 |
169 | /**
170 | * Returns the circle that has the greatest intersection area
171 | */
172 | function circleIntersection({
173 | collisionRect,
174 | droppableRects,
175 | droppableContainers,
176 | }) => {
177 | const collisions = [];
178 |
179 | for (const droppableContainer of droppableContainers) {
180 | const {id} = droppableContainer;
181 | const rect = droppableRects.get(id);
182 |
183 | if (rect) {
184 | const intersectionRatio = getCircleIntersection(rect, collisionRect);
185 |
186 | if (intersectionRatio > 0) {
187 | collisions.push({
188 | id,
189 | data: {droppableContainer, value: intersectionRatio},
190 | });
191 | }
192 | }
193 | }
194 |
195 | return collisions.sort(sortCollisionsDesc);
196 | };
197 | ```
198 |
199 | To learn more, refer to the implementation of the built-in collision detection algorithms.
200 |
--------------------------------------------------------------------------------
/api-documentation/context-provider/use-dnd-monitor.md:
--------------------------------------------------------------------------------
1 | # useDndMonitor
2 |
3 | The `useDndMonitor` hook can be used within components wrapped in a `DndContext` provider to monitor the different drag and drop events that happen for that `DndContext`.
4 |
5 | ```jsx
6 | import {DndContext, useDndMonitor} from '@dnd-kit/core';
7 |
8 | function App() {
9 | return (
10 |
11 |
12 |
13 | );
14 | }
15 |
16 | function Component() {
17 | // Monitor drag and drop events that happen on the parent `DndContext` provider
18 | useDndMonitor({
19 | onDragStart(event) {},
20 | onDragMove(event) {},
21 | onDragOver(event) {},
22 | onDragEnd(event) {},
23 | onDragCancel(event) {},
24 | });
25 | }
26 | ```
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/api-documentation/context-provider/usedndcontext.md:
--------------------------------------------------------------------------------
1 | # useDndContext
2 |
3 | For advanced use-cases, for example, if you're building your own presets on top of `@dnd-kit/core`, you may want to have access to the internal context of `` that the `useDraggable` and `useDroppable` have access to.
4 |
5 | ```jsx
6 | import {useDndContext} from '@dnd-kit/core';
7 |
8 | function CustomPreset() {
9 | const dndContext = useDndContext();
10 | }
11 | ```
12 |
13 | If you think the preset you're building could be useful to others, feel free to open up a PR for discussion in the `dnd-kit` repository.
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/api-documentation/draggable/README.md:
--------------------------------------------------------------------------------
1 | # Draggable
2 |
3 | 
4 |
5 | Use the `useDraggable` hook turn DOM nodes into draggable sources that can be picked up, moved and dropped over [droppable](../droppable/) containers.
6 |
7 | ## Usage
8 |
9 | The `useDraggable` hook isn't particularly opinionated about how your app should be structured.
10 |
11 | ### Node ref
12 |
13 | At minimum though, you need to pass the `setNodeRef` function that is returned by the `useDraggable` hook to a DOM element so that it can access the underlying DOM node and keep track of it to [detect collisions and intersections](../context-provider/collision-detection-algorithms.md) with other [droppable](../droppable/) elements.
14 |
15 | ```jsx
16 | import {useDraggable} from '@dnd-kit/core';
17 | import {CSS} from '@dnd-kit/utilities';
18 |
19 |
20 | function Draggable() {
21 | const {attributes, listeners, setNodeRef, transform} = useDraggable({
22 | id: 'unique-id',
23 | });
24 | const style = {
25 | transform: CSS.Translate.toString(transform),
26 | };
27 |
28 | return (
29 |
32 | );
33 | }
34 | ```
35 |
36 | {% hint style="info" %}
37 | Always try to use the DOM element that is most [semantic](https://developer.mozilla.org/en-US/docs/Glossary/Semantics) in the context of your app. \
38 | Check out our [Accessibility guide](../../guides/accessibility.md) to learn more about how you can help provide a better experience for screen readers.
39 | {% endhint %}
40 |
41 | ### Identifier
42 |
43 | The `id` argument is a string that should be a unique identifier, meaning there should be no other **draggable** elements that share that same identifier within a given [`DndContext`](../context-provider/) provider.
44 |
45 | ### Listeners
46 |
47 | The `useDraggable` hook requires that you attach `listeners` to the DOM node that you would like to become the activator to start dragging.
48 |
49 | While we could have attached these listeners manually to the node provided to `setNodeRef`, there are actually a number of key advantages to forcing the consumer to manually attach the listeners.
50 |
51 | #### Flexibility
52 |
53 | While many drag and drop libraries need to expose the concept of "drag handles", creating a drag handle with the `useDraggable` hook is as simple as manually attaching the listeners to a different DOM element than the one that is set as the draggable source DOM node:
54 |
55 | ```jsx
56 | import {useDraggable} from '@dnd-kit/core';
57 |
58 |
59 | function Draggable() {
60 | const {attributes, listeners, setNodeRef} = useDraggable({
61 | id: 'unique-id',
62 | });
63 |
64 | return (
65 |
66 | /* Some other content that does not activate dragging */
67 |
68 |
69 | );
70 | }
71 | ```
72 |
73 | {% hint style="info" %}
74 | When attaching the listeners to a different element than the node that is draggable, make sure you also attach the attributes to the same node that has the listeners attached so that it is still [accessible](../../guides/accessibility.md).
75 | {% endhint %}
76 |
77 | You can even have multiple drag handles if that makes sense in the context of your application:
78 |
79 | ```jsx
80 | import {useDraggable} from '@dnd-kit/core';
81 |
82 |
83 | function Draggable() {
84 | const {attributes, listeners, setNodeRef} = useDraggable({
85 | id: 'unique-id',
86 | });
87 |
88 | return (
89 |
90 |
91 | /* Some other content that does not activate dragging */
92 |
93 |
94 | );
95 | }
96 | ```
97 |
98 | #### Performance
99 |
100 | This strategy also means that we're able to use [React synthetic events](https://reactjs.org/docs/events.html), which ultimately leads to improved performance over manually attaching event listeners to each individual node.\
101 | \
102 | Why? Because rather than having to attach individual event listeners for each draggable DOM node, React attaches a single event listener for every type of event we listen to on the `document`. Once click on one of the draggable nodes happens, React's listener on the document dispatches a SyntheticEvent back to the original handler.
103 |
104 | ### Transforms
105 |
106 | In order to actually see your draggable items move on screen, you'll need to move the item using CSS. You can use inline styles, CSS variables, or even CSS-in-JS libraries to pass the `transform` property as CSS to your draggable element.
107 |
108 | {% hint style="success" %}
109 | For performance reasons, we strongly recommend you use the **`transform`** CSS property to move your draggable item on the screen, as other positional properties such as **`top`**, **`left`** or **`margin`** can cause expensive repaints. Learn more about [CSS transforms](https://developer.mozilla.org/en-US/docs/Web/CSS/transform).
110 | {% endhint %}
111 |
112 | After an item starts being dragged, the `transform` property will be populated with the `translate` coordinates you'll need to move the item on the screen. The `transform` object adheres to the following shape: `{x: number, y: number, scaleX: number, scaleY: number}`
113 |
114 | The `x` and `y` coordinates represent the delta from the point of origin of your draggable element since it started being dragged.
115 |
116 | The `scaleX` and `scaleY` properties represent the difference in scale between the item that is dragged and the droppable container it is currently over. This is useful for building interfaces where the draggable item needs to adapt to the size of the droppable container it is currently over.
117 |
118 | The `CSS` helper is entirely optional; it's a convenient helper for generating [CSS transform ](https://developer.mozilla.org/en-US/docs/Web/CSS/transform)strings, and is equivalent to manually constructing the string as such:
119 |
120 | ```javascript
121 | CSS.Translate.toString(transform) ===
122 | `translate3d(${translate.x}, ${translate.y}, 0)`
123 | ```
124 |
125 | ### Attributes
126 |
127 | The `useDraggable` hook **** provides a set of sensible default attributes for draggable items. We recommend you attach these to the HTML element you are attaching the draggable listeners to.
128 |
129 | We encourage you to manually attach the attributes that you think make sense in the context of your application rather than using them all without considering whether it makes sense to do so.
130 |
131 | For example, if the HTML element you are attaching the `useDraggable` `listeners` to is already a semantic `button`, although it's harmless to do so, there's no need to add the `role="button"` attribute, since that is already the default role.
132 |
133 | | Attribute | Default value | Description |
134 | | ---------------------- | ------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
135 | | `role` | `"button"` |
If possible, we recommend you use a semantic <button> element for the DOM element you plan on attaching draggable listeners to.
In case that's not possible, make sure you include the role="button"attribute, which is the default value.
|
136 | | `tabIndex` | `"0"` | In order for your draggable elements to receive keyboard focus, they **need** to have the `tabindex` attribute set to `0` if they are not natively interactive elements (such as the HTML `button` element). For this reason, the `useDraggable` hook sets the `tabindex="0"` attribute by default. |
137 | | `aria-roledescription` | `"draggable"` | While `draggable` is a sensible default, we recommend you customize this value to something that is tailored to the use case you are building. |
138 | | `aria-describedby` | `"DndContext-[uniqueId]"` | Each draggable item is provided a unique `aria-describedby` ID that points to the [screen reader instructions](../context-provider/#screen-reader-instructions) to be read out when a draggable item receives focus. |
139 |
140 | To learn more about the best practices for making draggable interfaces accessible, read the full accessibility guide:
141 |
142 | {% content-ref url="../../guides/accessibility.md" %}
143 | [accessibility.md](../../guides/accessibility.md)
144 | {% endcontent-ref %}
145 |
146 | ### Recommendations
147 |
148 | #### `touch-action`
149 |
150 | We highly recommend you specify the `touch-action` CSS property for all of your draggable elements.
151 |
152 | > The **`touch-action`** CSS property sets how an element's region can be manipulated by a touchscreen user (for example, by zooming features built into the browser).\
153 | > \
154 | > Source: [MDN](https://developer.mozilla.org/en-US/docs/Web/CSS/touch-action)
155 |
156 | In general, we recommend you set the `touch-action` property to `none` for draggable elements in order to prevent scrolling on mobile devices.
157 |
158 | {% hint style="info" %}
159 | For [Pointer Events,](../sensors/pointer.md) there is no way to prevent the default behaviour of the browser on touch devices when interacting with a draggable element from the pointer event listeners. Using `touch-action: none;` is the only way to reliably prevent scrolling for pointer events.
160 |
161 | Further, using `touch-action: none;` is currently the only reliable way to prevent scrolling in iOS Safari for both Touch and Pointer events.
162 | {% endhint %}
163 |
164 | If your draggable item is part of a scrollable list, we recommend you use a drag handle and set `touch-action` to `none` only for the drag handle, so that the contents of the list can still be scrolled, but that initiating a drag from the drag handle does not scroll the page.
165 |
166 | Once a `pointerdown` or `touchstart` event has been initiated, any changes to the `touch-action` value will be ignored. Programmatically changing the `touch-action` value for an element from `auto` to `none` after a pointer or touch event has been initiated will not result in the user agent aborting or suppressing any default behavior for that event for as long as that pointer is active (for more details, refer to the [Pointer Events Level 2 Spec](https://www.w3.org/TR/pointerevents2/#determining-supported-touch-behavior)).
167 |
168 | ## Drag Overlay
169 |
170 | The `` component provides a way to render a draggable overlay that is removed from the normal document flow and is positioned relative to the viewport.
171 |
172 | .png>)
173 |
174 | To learn more about how to use drag overlays, read the in-depth guide:
175 |
176 | {% content-ref url="drag-overlay.md" %}
177 | [drag-overlay.md](drag-overlay.md)
178 | {% endcontent-ref %}
179 |
--------------------------------------------------------------------------------
/api-documentation/draggable/clone.md:
--------------------------------------------------------------------------------
1 | # DraggableClone
2 |
3 |
--------------------------------------------------------------------------------
/api-documentation/draggable/drag-overlay.md:
--------------------------------------------------------------------------------
1 | # Drag Overlay
2 |
3 | The `` component provides a way to render a draggable overlay that is removed from the normal document flow and is positioned relative to the viewport.
4 |
5 | 
6 |
7 | ## When should I use a drag overlay?
8 |
9 | Depending on your use-case, you may want to use a drag overlay rather than transforming the original draggable source element that is connected to the [`useDraggable`](usedraggable.md) hook:
10 |
11 | * If you'd like to **show a preview** of where the draggable source will be when dropped, you can update the position of the draggable source while dragging without affecting the drag overlay.
12 | * If your item needs to **move from one container to another while dragging**, we strongly recommend you use the `` component so the draggable item can unmount from its original container while dragging and mount back into a different container without affecting the drag overlay.
13 | * If your draggable item is within a **scrollable container,** we also recommend you use a ``, otherwise you'll need to set the draggable element to `position: fixed` yourself so the item isn't restricted to the overflow and stacking context of its scroll container, and can move without being affected by the scroll position of its container.
14 | * If your `useDraggable` items are within a **virtualized list**, you will absolutely want to use a drag overlay, since the original drag source can unmount while dragging as the virtualized container is scrolled.
15 | * If you want **smooth drop animations** without the effort of building them yourself.
16 |
17 | ## Usage
18 |
19 | You may render any valid JSX within the children of the ``.
20 |
21 | The `` component should **remain mounted at all times** so that it can perform the drop animation. If you conditionally render the `` component, drop animations will not work.
22 |
23 | As a rule of thumb, try to render the `` outside of your draggable components, and follow the [presentational component pattern ](drag-overlay.md#presentational-components)to maintain a good separation of concerns.
24 |
25 | Instead, you should conditionally render the children passed to the ``:
26 |
27 | {% tabs %}
28 | {% tab title="App.jsx" %}
29 | ```jsx
30 | import React, {useState} from 'react';
31 | import {DndContext, DragOverlay} from '@dnd-kit/core';
32 |
33 | import {Draggable} from './Draggable';
34 |
35 | /* The implementation details of and are not
36 | * relevant for this example and are therefore omitted. */
37 |
38 | function App() {
39 | const [items] = useState(['1', '2', '3', '4', '5']);
40 | const [activeId, setActiveId] = useState(null);
41 |
42 | return (
43 |
44 |
45 | {items.map(id =>
46 |
47 |
48 |
49 | )}
50 |
51 |
52 |
53 | {activeId ? (
54 |
55 | ): null}
56 |
57 |
58 | );
59 |
60 | function handleDragStart(event) {
61 | setActiveId(event.active.id);
62 | }
63 |
64 | function handleDragEnd() {
65 | setActiveId(null);
66 | }
67 | }
68 | ```
69 | {% endtab %}
70 |
71 | {% tab title="Draggable.jsx" %}
72 | ```jsx
73 | import React from 'react';
74 | import {useDraggable} from '@dnd-kit/core';
75 |
76 | function Draggable(props) {
77 | const {attributes, listeners, setNodeRef} = useDraggable({
78 | id: props.id,
79 | });
80 |
81 | return (
82 |
83 | {props.children}
84 |
85 | );
86 | }
87 | ```
88 | {% endtab %}
89 | {% endtabs %}
90 |
91 | ## Patterns
92 |
93 | ### Presentational components
94 |
95 | While this is an optional pattern, we recommend that the components you intend to make draggable be [presentational components ](https://medium.com/@dan\_abramov/smart-and-dumb-components-7ca2f9a7c7d0)that are decoupled from `@dnd-kit`.
96 |
97 | Using this pattern, create a presentational version of your component that you intend on rendering within the drag overlay, and another version that is draggable and renders the presentational component.
98 |
99 | #### Wrapper nodes
100 |
101 | As you may have noticed from the example above, we can create small abstract components that render a wrapper node and make any children rendered within draggable:
102 |
103 | {% tabs %}
104 | {% tab title="Draggable.jsx" %}
105 | ```jsx
106 | import React from 'react';
107 | import {useDraggable} from '@dnd-kit/core';
108 |
109 | function Draggable(props) {
110 | const Element = props.element || 'div';
111 | const {attributes, listeners, setNodeRef} = useDraggable({
112 | id: props.id,
113 | });
114 |
115 | return (
116 |
117 | {props.children}
118 |
119 | );
120 | }
121 | ```
122 | {% endtab %}
123 | {% endtabs %}
124 |
125 | Using this pattern, we can then render our presentational components within `` and within ``:
126 |
127 | {% tabs %}
128 | {% tab title="App.jsx" %}
129 | ```jsx
130 | import React, {useState} from 'react';
131 | import {DndContext, DragOverlay} from '@dnd-kit/core';
132 |
133 | import {Draggable} from './Draggable';
134 |
135 | /* The implementation details of is not
136 | * relevant for this example and therefore omitted. */
137 |
138 | function App() {
139 | const [isDragging, setIsDragging] = useState(false);
140 |
141 | return (
142 |
143 |
144 |
145 |
146 |
147 |
148 | {isDragging ? (
149 |
150 | ): null}
151 |
152 |
153 | );
154 |
155 | function handleDragStart() {
156 | setIsDragging(true);
157 | }
158 |
159 | function handleDragEnd() {
160 | setIsDragging(false);
161 | }
162 | }
163 | ```
164 | {% endtab %}
165 | {% endtabs %}
166 |
167 | #### Ref forwarding
168 |
169 | Use the[ ref forwarding pattern](https://reactjs.org/docs/forwarding-refs.html) to connect your presentational components to the `useDraggable` hook:
170 |
171 | ```jsx
172 | import React, {forwardRef} from 'react';
173 |
174 | const Item = forwardRef(({children, ...props}, ref) => {
175 | return (
176 |
{children}
177 | )
178 | });
179 | ```
180 |
181 | This way, you can create two versions of your component, one that is presentational, and one that is draggable and renders the presentational component **without the need for additional wrapper elements**:
182 |
183 | ```jsx
184 | import React from 'react';
185 | import {useDraggable} from '@dnd-kit/core';
186 |
187 | function DraggableItem(props) {
188 | const {attributes, listeners, setNodeRef} = useDraggable({
189 | id: props.id,
190 | });
191 |
192 | return (
193 |
194 | {value}
195 |
196 | )
197 | });
198 | ```
199 |
200 | ### Portals
201 |
202 | The drag overlay is not rendered in a portal by default. Rather, it is rendered in the container where it is rendered.
203 |
204 | If you would like to render the `` in a different container than where it is rendered, import the [`createPortal`](https://reactjs.org/docs/portals.html) helper from `react-dom`:
205 |
206 | ```jsx
207 | import React, {useState} from 'react';
208 | import {createPortal} from 'react-dom';
209 | import {DndContext, DragOverlay} from '@dnd-kit/core';
210 |
211 | function App() {
212 | return (
213 |
214 | {createPortal(
215 | {/* ... */},
216 | document.body,
217 | )}
218 |
219 | );
220 | }
221 | ```
222 |
223 | ## Props
224 |
225 | ```typescript
226 | {
227 | adjustScale?: boolean;
228 | children?: React.ReactNode;
229 | className?: string;
230 | dropAnimation?: DropAnimation | null;
231 | style?: React.CSSProperties;
232 | transition?: string | TransitionGetter;
233 | modifiers?: Modifiers;
234 | wrapperElement?: keyof JSX.IntrinsicElements;
235 | zIndex?: number;
236 | }
237 | ```
238 |
239 | ### Children
240 |
241 | You may render any valid JSX within the children of the ``. However, **make sure that the components rendered within the drag overlay do not use the `useDraggable` hook**.
242 |
243 | Prefer conditionally rendering the `children` of `` rather than conditionally rendering ``, otherwise drop animations will not work.
244 |
245 | ### Class name and inline styles
246 |
247 | If you'd like to customize the[ wrapper element](drag-overlay.md#wrapper-element) that the `DragOverlay`'s children are rendered into, use the `className` and `style` props:
248 |
249 | ```jsx
250 |
256 | {/* ... */}
257 |
258 | ```
259 |
260 | ### Drop animation
261 |
262 | Use the `dropAnimation` prop to configure the drop animation.
263 |
264 | ```typescript
265 | interface DropAnimation {
266 | duration: number;
267 | easing: string;
268 | }
269 | ```
270 |
271 | The `duration` option should be a number, in `milliseconds`. The default value is `250` milliseconds. The `easing` option should be a string that represents a valid [CSS easing function](https://developer.mozilla.org/en-US/docs/Web/CSS/easing-function). The default easing is `ease`.
272 |
273 | ```jsx
274 |
278 | {/* ... */}
279 |
280 | ```
281 |
282 | To disable drop animations, set the `dropAnimation` prop to `null`.
283 |
284 | ```jsx
285 |
286 | {/* ... */}
287 |
288 | ```
289 |
290 | {% hint style="warning" %}
291 | The `` component should **remain mounted at all times** so that it can perform the drop animation. If you conditionally render the `` component, drop animations will not work.
292 | {% endhint %}
293 |
294 | ### Modifiers
295 |
296 | Modifiers let you dynamically modify the movement coordinates that are detected by sensors. They can be used for a wide range of use-cases, which you can learn more about by reading the [Modifiers](../modifiers.md) documentation.
297 |
298 | For example, you can use modifiers to restrict the movement of the `` to the bounds of the window:
299 |
300 | ```jsx
301 | import {DndContext, DragOverlay} from '@dnd-kit';
302 | import {
303 | restrictToWindowEdges,
304 | } from '@dnd-kit/modifiers';
305 |
306 | function App() {
307 | return (
308 |
309 | {/* ... */}
310 |
311 | {/* ... */}
312 |
313 |
314 | )
315 | }
316 | ```
317 |
318 | ### Transition
319 |
320 | By default, the `` component does not have any transitions, unless activated by the [`Keyboard` sensor](../sensors/keyboard.md). Use the `transition` prop to create a function that returns the transition based on the [activator event](../sensors/#activators). The default implementation is:
321 |
322 | ```javascript
323 | function defaultTransition(activatorEvent) {
324 | const isKeyboardActivator = activatorEvent instanceof KeyboardEvent;
325 |
326 | return isKeyboardActivator ? 'transform 250ms ease' : undefined;
327 | };
328 | ```
329 |
330 | ### Wrapper element
331 |
332 | By default, the `` component renders your elements within a `div` element. If your draggable elements are list items, you'll want to update the `` component to render a `ul` wrapper instead, since wrapping a `li` item without a parent `ul` is invalid HTML:
333 |
334 | ```jsx
335 |
336 | {/* ... */}
337 |
338 | ```
339 |
340 | ### `z-index`
341 |
342 | The `zIndex` prop sets the [z-order](https://developer.mozilla.org/en-US/docs/Web/CSS/z-index) of the drag overlay. The default value is `999` for compatibility reasons, but we highly recommend you use a lower value.
343 |
--------------------------------------------------------------------------------
/api-documentation/draggable/usedraggable.md:
--------------------------------------------------------------------------------
1 | # useDraggable
2 |
3 | 
4 |
5 | ## Arguments
6 |
7 | ```typescript
8 | interface UseDraggableArguments {
9 | id: string | number;
10 | attributes?: {
11 | role?: string;
12 | roleDescription?: string;
13 | tabIndex?: number;
14 | },
15 | data?: Record;
16 | disabled?: boolean;
17 | }
18 | ```
19 |
20 | ### Identifier
21 |
22 | The `id` argument is a `string` or `number` that should be a unique identifier, meaning there should be no other **draggable** elements that share that same identifier within a given [`DndContext`](../context-provider/) provider.
23 |
24 | If you're building a component that uses both the `useDraggable` and `useDroppable` hooks, they can both share the same identifier since draggable elements are stored in a different key-value store than droppable elements.
25 |
26 | ### Data
27 |
28 | The `data` argument is for advanced use-cases where you may need access to additional data about the draggable element in event handlers, modifiers or custom sensors.
29 |
30 | For example, if you were building a sortable preset, you could use the `data` attribute to store the index of the draggable element within a sortable list to access it within a custom sensor.
31 |
32 | ```jsx
33 | const {setNodeRef} = useDraggable({
34 | id: props.id,
35 | data: {
36 | index: props.index,
37 | },
38 | });
39 | ```
40 |
41 | Another more advanced example where the `data` argument can be useful is create relationships between draggable nodes and droppable areas, for example, to specify which types of droppable nodes your draggable node can be dropped on:
42 |
43 | ```jsx
44 | import {DndContext, useDraggable, useDroppable} from '@dnd-kit/core';
45 |
46 | function Droppable() {
47 | const {setNodeRef} = useDroppable({
48 | id: 'droppable',
49 | data: {
50 | type: 'type1',
51 | },
52 | });
53 |
54 | /* ... */
55 | }
56 |
57 | function Draggable() {
58 | const {attributes, listeners, setNodeRef, transform} = useDraggable({
59 | id: 'draggable',
60 | data: {
61 | supports: ['type1', 'type2'],
62 | },
63 | });
64 |
65 | /* ... */
66 | }
67 |
68 | function App() {
69 | return (
70 |
71 | /* ... */
72 |
73 | );
74 |
75 | function handleDragEnd(event) {
76 | const {active, over} = event;
77 |
78 | if (over && active.data.current.supports.includes(over.data.current.type)) {
79 | // do stuff
80 | }
81 | }
82 | }
83 | ```
84 |
85 | ### Disabled
86 |
87 | Since [hooks cannot be conditionally invoked](https://reactjs.org/docs/hooks-rules.html), use the `disabled` argument and set it to `true` if you need to temporarily disable a `draggable` element.
88 |
89 | ### Attributes
90 |
91 | The default values for the `attributes` property are sensible defaults that should cover a wide range of use cases, but there is no one-size-fits-all solution.
92 |
93 | You know your application best, and we encourage you to manually attach only the attributes that you think make sense in the context of your application rather than using them all without considering whether it makes sense to do so.
94 |
95 | For example, if the HTML element you are attaching the `useDraggable` `listeners` to is already a native HTML `button` element, although it's harmless to do so, there's no need to add the `role="button"` attribute, since that is already the default role of `button`.
96 |
97 | #### Role
98 |
99 | The ARIA `"role"` attribute lets you explicitly define the role for an element, which communicates its purpose to assistive technologies.
100 |
101 | The default value for the `"role"` attribute is `"button"`.
102 |
103 | {% hint style="info" %}
104 | If it makes sense in the context of what you are building, we recommend that you leverage the native HTML `