Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
9128fca
wip: revision 1
weronikaolejniczak Dec 15, 2025
8a3716f
fix: update instruction when dragging
weronikaolejniczak Dec 15, 2025
e092e98
fix: change indicator placement
weronikaolejniczak Dec 15, 2025
9693c1e
fix: auto-open newly nested accordions
weronikaolejniczak Dec 15, 2025
5e2f9ce
fix: only show inner-most indicator
weronikaolejniczak Dec 15, 2025
4e8a719
fix: remove unused import
weronikaolejniczak Dec 15, 2025
ba53905
feat: add consolidated file demo
weronikaolejniczak Dec 15, 2025
043b5c3
feat: add a simple documentation
weronikaolejniczak Dec 15, 2025
bf22470
feat: remove code-block
weronikaolejniczak Dec 15, 2025
2d2558d
fix: custom_typings type augmentation for css prop
weronikaolejniczak Dec 15, 2025
0f70cb7
feat: update current dnd docs
weronikaolejniczak Dec 15, 2025
ef6fcda
feat: add grab icon
weronikaolejniczak Dec 15, 2025
c2d97e1
refactor: add LineIndicator component
weronikaolejniczak Dec 15, 2025
a4b9381
feat: implement blocked panels
weronikaolejniczak Dec 15, 2025
b5956f2
fix: drag and drop page title
weronikaolejniczak Dec 16, 2025
91e9e14
fix: change panel padding size
weronikaolejniczak Dec 16, 2025
b4a7f15
fix: make overflow visible in accordion content
weronikaolejniczak Dec 16, 2025
4a16614
chore: add comments
weronikaolejniczak Dec 16, 2025
292a30e
fix: remove collapsing on drag, z-index and add comment
weronikaolejniczak Dec 16, 2025
95a795c
fix: remove redundant onDragEnter
weronikaolejniczak Dec 16, 2025
7c6d66a
chore: add a helpful comment about key prop
weronikaolejniczak Dec 16, 2025
9346fa6
chore: add another helpful comment
weronikaolejniczak Dec 16, 2025
5996ca7
chore: add a comment regarding relative position
weronikaolejniczak Dec 16, 2025
0009d73
refactor: dry out the children... wth
weronikaolejniczak Dec 16, 2025
7dd2647
fix: incorrect hover effects
weronikaolejniczak Dec 16, 2025
65ad350
fix: make reordering possible for blocked panels
weronikaolejniczak Dec 16, 2025
f8a7bca
chore: set module to nodenext
weronikaolejniczak Dec 16, 2025
1ec2ebe
chore: remove redundant pragma
weronikaolejniczak Dec 16, 2025
b45b40f
fix: block descendant drop
weronikaolejniczak Dec 16, 2025
dc40d14
refactor: create meaningful variables
weronikaolejniczak Dec 16, 2025
139d32d
feat: add a11y roles
weronikaolejniczak Dec 19, 2025
58b111f
feat: add aria attributes to tree
weronikaolejniczak Dec 19, 2025
26047bc
feat: add a11y admonition
weronikaolejniczak Dec 19, 2025
2f74b15
feat: update styles
weronikaolejniczak Dec 19, 2025
bd9a95d
feat: remove grab transition
weronikaolejniczak Dec 19, 2025
4d1b4c7
refactor: rename style
weronikaolejniczak Dec 19, 2025
f49811a
feat: handle keyboard navigation
weronikaolejniczak Dec 19, 2025
5457455
feat: add more actions
weronikaolejniczak Dec 19, 2025
027345a
feat: update a11y admonition
weronikaolejniczak Dec 19, 2025
3f9b133
fix: rephrase a11y admonition
weronikaolejniczak Dec 19, 2025
666bf11
refactor: utility functions
weronikaolejniczak Dec 19, 2025
df2370b
fix: remove misleading comment
weronikaolejniczak Dec 19, 2025
f6516d7
fix: small issue
weronikaolejniczak Dec 19, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 46 additions & 20 deletions packages/website/docs/components/display/drag-and-drop.mdx
Copy link
Contributor Author

@weronikaolejniczak weronikaolejniczak Dec 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is some opinionated formatting in this diff so I'll highlight the most important changes with comments 👇🏻

Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,25 @@ keywords: [EuiDragDropContext, EuiDroppable, EuiDraggable]

# Drag and drop

An extension of [@hello-pangea/dnd](https://github.com/hello-pangea/dnd) (which is an actively maintained fork of [react-beautiful-dnd](https://github.com/atlassian/react-beautiful-dnd)) with a compatible API and built-in style opinions. Functionality results from 3 components working together:
```mdx-code-block
import { EuiLink } from '@elastic/eui';
```

An extension of <EuiLink href="https://github.com/hello-pangea/dnd" target="_blank">@hello-pangea/dnd</EuiLink> (which is an actively maintained fork of <EuiLink href="https://github.com/atlassian/react-beautiful-dnd" target="_blank">react-beautiful-dnd</EuiLink>) with a compatible API and built-in style opinions. Functionality results from 3 components working together:

- `<EuiDragDropContext />`: Section of your application containing the draggable elements and the drop targets.
- `<EuiDroppable />`: Area into which items can be dropped. Contains one or more `<EuiDraggable />`.
- `<EuiDraggable />`: Items that can be dragged. Must be part of an `<EuiDroppable />`.

* `<EuiDragDropContext />`: Section of your application containing the draggable elements and the drop targets.
* `<EuiDroppable />`: Area into which items can be dropped. Contains one or more `<EuiDraggable />`.
* `<EuiDraggable />`: Items that can be dragged. Must be part of an `<EuiDroppable />`
:::accessibility Consider your users and use case

:::warning Consider your users and use case
Drag and drop is often less suitable than standard form inputs. It relies on spatial orientation, which can be difficult for screen reader users. Keyboard navigation typically does not afford the same nuanced manipulation as a mouse. EUI maintains accessibility support but carefully consider your users' context when choosing this pattern.
Copy link
Contributor Author

@weronikaolejniczak weronikaolejniczak Dec 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Opinionated rewrite of the previous admonition that was long, used some hefty words and, in my opinion, didn't get the point across effectively. I can drop if someone disagrees.


:::

Drag and drop interfaces are not well-adapted to many cases, and may be less suitable than other form types for data operations. For instance, drag and drop interaction relies heavily on spatial orientation that may not be entirely valid to all users (e.g., screen readers as the sole source of information). Similarly, users navigating by keyboard may not be afforded nuanced, dual-axis drag item manipulation.
:::warning Limitations

EUI (largely due to the great work already in @hello-pangea/dnd) has and will continue to ensure accessibility where possible. With that in mind, keep your users' working context in mind.
One of the limitations of <EuiLink href="https://github.com/hello-pangea/dnd" target="_blank">@hello-pangea/dnd</EuiLink> is **nested drag and drop** (dragging elements between nesting levels). For this use case, we recommend using <EuiLink href="https://atlassian.design/components/pragmatic-drag-and-drop/about" target="_blank">Pragmatic drag and drop</EuiLink>. Check out our [Nested drag and drop pattern](../../patterns/nested-drag-and-drop/index.mdx) for a simplified example of how to implement it.
Comment on lines +23 to +25
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added an admonition to warn users about the limitations of our drag and drop components and redirect them to the "Nested drag and drop" pattern.


:::

Expand All @@ -28,16 +36,16 @@ All **EuiDragDropContext** elements are discrete and isolated; **EuiDroppables**

**EuiDragDropContext** handles all events but makes no assumptions about the result of a drop event. As such, the following event handlers are available:

* `onBeforeDragStart`
* `onDragStart`
* `onDragUpdate`
* `onDragEnd` (required)
- `onBeforeDragStart`
- `onDragStart`
- `onDragUpdate`
- `onDragEnd` (required)

EUI also provides methods for helping to deal to common action types:

* `reorder`: change an item's location in a droppable area
* `copy`: create a duplicate of an item in a different droppable area
* `move`: move an item to a different droppable area
- `reorder`: change an item's location in a droppable area
- `copy`: create a duplicate of an item in a different droppable area
- `move`: move an item to a different droppable area

```tsx interactive
import React, { useState } from 'react';
Expand Down Expand Up @@ -77,7 +85,6 @@ export default () => {
</EuiDragDropContext>
);
};

```

## Simple item reorder
Expand Down Expand Up @@ -109,13 +116,15 @@ const makeList = (number, start = 1) =>

export default () => {
const [list, setList] = useState(makeList(3));

const onDragEnd = ({ source, destination }) => {
if (source && destination) {
const items = euiDragDropReorder(list, source.index, destination.index);

setList(items);
}
};

return (
<EuiDragDropContext onDragEnd={onDragEnd}>
<EuiDroppable droppableId="DROPPABLE_AREA" spacing="m" withPanel>
Expand All @@ -133,7 +142,6 @@ export default () => {
</EuiDragDropContext>
);
};

```

## Custom drag handle
Expand All @@ -143,7 +151,9 @@ By default the entire element surface can initiate a drag. To specify an element
The `provided` parameter on the **EuiDraggable** `children` render prop has all data required for functionality. Along with the `customDragHandle` flag,`provided.dragHandleProps` needs to be added to the intended handle element.

:::accessibility Accessibility requirement

**Icon-only** custom drag handles require an accessible label. Add an `aria-label="Drag handle"` attribute to your React component or HTML element that receives`provided.dragHandleProps`.

:::

```tsx interactive
Expand Down Expand Up @@ -172,13 +182,15 @@ const makeList = (number, start = 1) =>

export default () => {
const [list, setList] = useState(makeList(3));

const onDragEnd = ({ source, destination }) => {
if (source && destination) {
const items = euiDragDropReorder(list, source.index, destination.index);

setList(items);
}
};

return (
<EuiDragDropContext onDragEnd={onDragEnd}>
<EuiDroppable
Expand Down Expand Up @@ -218,7 +230,6 @@ export default () => {
</EuiDragDropContext>
);
};

```

## Interactive elements
Expand Down Expand Up @@ -252,13 +263,15 @@ const makeList = (number, start = 1) =>

export default () => {
const [list, setList] = useState(makeList(3));

const onDragEnd = ({ source, destination }) => {
if (source && destination) {
const items = euiDragDropReorder(list, source.index, destination.index);

setList(items);
}
};

return (
<EuiDragDropContext onDragEnd={onDragEnd}>
<EuiDroppable
Expand Down Expand Up @@ -302,7 +315,6 @@ export default () => {
</EuiDragDropContext>
);
};

```

## Move between lists
Expand Down Expand Up @@ -366,6 +378,7 @@ export default () => {
}
}
};

return (
<EuiDragDropContext onDragEnd={onDragEnd}>
<EuiFlexGroup>
Expand Down Expand Up @@ -437,7 +450,6 @@ export default () => {
</EuiDragDropContext>
);
};

```

## Distinguish droppable areas by type
Expand Down Expand Up @@ -474,6 +486,7 @@ export default () => {
const [list1, setList1] = useState(makeList(3));
const [list2, setList2] = useState(makeList(3, 4));
const [list3, setList3] = useState(makeList(3, 7));

const onDragEnd = ({ source, destination }) => {
const lists = {
DROPPABLE_AREA_TYPE_1: list1,
Expand Down Expand Up @@ -509,6 +522,7 @@ export default () => {
}
}
};

return (
<EuiDragDropContext onDragEnd={onDragEnd}>
<EuiFlexGroup>
Expand Down Expand Up @@ -576,7 +590,6 @@ export default () => {
</EuiDragDropContext>
);
};

```

## Copyable items
Expand Down Expand Up @@ -617,22 +630,27 @@ export default () => {
const [isItemRemovable, setIsItemRemovable] = useState(false);
const [list1, setList1] = useState(makeList(3));
const [list2, setList2] = useState([]);

const lists = { DROPPABLE_AREA_COPY_1: list1, DROPPABLE_AREA_COPY_2: list2 };

const actions = {
DROPPABLE_AREA_COPY_1: setList1,
DROPPABLE_AREA_COPY_2: setList2,
};

const remove = (droppableId, index) => {
const list = Array.from(lists[droppableId]);
list.splice(index, 1);

actions[droppableId](list);
};

const onDragUpdate = ({ source, destination }) => {
const shouldRemove =
!destination && source.droppableId === 'DROPPABLE_AREA_COPY_2';
setIsItemRemovable(shouldRemove);
};

const onDragEnd = ({ source, destination }) => {
if (source && destination) {
if (source.droppableId === destination.droppableId) {
Expand Down Expand Up @@ -664,6 +682,7 @@ export default () => {
remove(source.droppableId, source.index);
}
};

return (
<EuiDragDropContext onDragEnd={onDragEnd} onDragUpdate={onDragUpdate}>
<EuiFlexGroup>
Expand Down Expand Up @@ -787,6 +806,7 @@ export default () => {
const [isPopoverOpen, setIsPopoverOpen] = useState(false);

const [list, setList] = useState(makeList(3));

const onDragEnd: OnDragEndResponder = ({ source, destination }) => {
if (source && destination) {
const items = euiDragDropReorder(list, source.index, destination.index);
Expand Down Expand Up @@ -945,16 +965,19 @@ export default () => {
const [list, setList] = useState([1, 2]);
const [list1, setList1] = useState(makeList(3));
const [list2, setList2] = useState(makeList(3, 4));

const lists = {
COMPLEX_DROPPABLE_PARENT: list,
COMPLEX_DROPPABLE_AREA_1: list1,
COMPLEX_DROPPABLE_AREA_2: list2,
};

const actions = {
COMPLEX_DROPPABLE_PARENT: setList,
COMPLEX_DROPPABLE_AREA_1: setList1,
COMPLEX_DROPPABLE_AREA_2: setList2,
};

const onDragEnd = ({ source, destination }) => {
if (source && destination) {
if (source.droppableId === destination.droppableId) {
Expand All @@ -980,6 +1003,7 @@ export default () => {
}
}
};

return (
<EuiDragDropContext onDragEnd={onDragEnd}>
<EuiDroppable
Expand Down Expand Up @@ -1039,7 +1063,9 @@ export default () => {

## Props

```mdx-code-block
import docgen from '@elastic/eui-docgen/dist/components/drag_and_drop';
```

<PropTable definition={docgen.EuiDragDropContext} />
<PropTable definition={docgen.EuiDraggable} />
Expand Down
Loading