Install react-easy-sort
mainYou can install react-easy-sort using either yarn or npm.
yarn add react-easy-sortor
npm install react-easy-sort --saverepository·main·Indexed 41 days ago
https://github.com/valentinh/react-easy-sortA React component library for sorting items in lists or grids using drag and drop. Version 1.8.0 supports horizontal and vertical layouts, native grid layouts, and is mobile-friendly. It provides SortableList, SortableItem, and SortableKnob components to manage sorting gestures and drag handles, along with utility functions like arrayMove and findItemIndexAtPosition.
You can install react-easy-sort using either yarn or npm.
yarn add react-easy-sortor
npm install react-easy-sort --saveTo prevent default browser behaviors from interfering with the drag-and-drop experience, apply the following CSS rules to your items:
user-select: none;: Disables content selection (the blue highlight box) while dragging.pointer-events: none;: Required for certain browsers if your items contain images.To implement a sortable list, wrap your items in a SortableList component. Each item that can be moved must be wrapped in a SortableItem. If you want to restrict the drag gesture to a specific part of the item (like a handle), wrap that specific element in a SortableKnob.
SortableList manages the drag-and-drop state, handles auto-scrolling, and provides callbacks for the sorting lifecycle. SortableItem registers the DOM element with the list, and SortableKnob registers a specific element as a valid drag handle.
<SortableList onSortEnd={(oldIndex, newIndex) => handleSort(oldIndex, newIndex)}>
{items.map((item, index) => (
<SortableItem key={item.id}>
<div className="item">
<SortableKnob>
<span className="handle">⠿</span>
</SortableKnob>
{item.content}
</div>
</SortableItem>
))}
</SortableList>To implement a sortable list, use SortableList as the container and wrap each list item in a SortableItem. You must provide an onSortEnd callback to update your state when the sorting gesture is completed. It is recommended to use a utility like arrayMoveImmutable from the array-move package to handle the array reordering.
import SortableList, { SortableItem } from 'react-easy-sort'
import { arrayMoveImmutable } from 'array-move'
const App = () => {
const [items, setItems] = React.useState(['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I'])
const onSortEnd = (oldIndex: number, newIndex: number) => {
setItems((array) => arrayMoveImmutable(array, oldIndex, newIndex))
}
return (
<SortableList onSortEnd={onSortEnd} className="list" draggedItemClassName="dragged">
{items.map((item) => (
<SortableItem key={item}>
<div className="item">{item}</div>
</SortableItem>
))}
</SortableList>
)
}If you do not want the entire item to be draggable, wrap a specific area of the item in a SortableKnob. This allows the user to initiate the drag gesture only through that specific element. Like SortableItem, the child of SortableKnob must be a single React element that can receive a ref (use React.forwardRef() for custom components).
import SortableList, { SortableItem, SortableKnob } from 'react-easy-sort'
import arrayMove from 'array-move'
const App = () => {
const [items, setItems] = React.useState(['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I'])
const onSortEnd = (oldIndex: number, newIndex: number) => {
setItems((array) => arrayMove(array, oldIndex, newIndex))
}
return (
<SortableList onSortEnd={onSortEnd} className="list" draggedItemClassName="dragged">
{items.map((item) => (
<SortableItem key={item}>
<div className="item">
<SortableKnob>
<div>Drag me</div>
</SortableKnob>
{item}
</div>
</SortableItem>
))}
</SortableList>
)
}SortableItem component does not take any props other than its child. The child must be a single React element that can receive a ref. If you are passing a custom component as a child, you must wrap it with React.forwardRef().The SortableList component accepts the following props:
| Name | Description | Type | Default |
|---|---|---|---|
as | Determines html tag for the container element | keyof JSX.IntrinsicElements | div |
onSortStart | Called when the user starts a sorting gesture | () => void | - |
onSortMove | Called when the dragged item changes position during a sorting gesture | (newIndex: number) => void | - |
onSortEnd* | Called when the user finishes a sorting gesture. | (oldIndex: number, newIndex: number) => void | - |
draggedItemClassName | Class applied to the item being dragged | string | - |
lockAxis | Determines if an axis should be locked | 'x' | 'y' | |
allowDrag | Determines whether items can be dragged | boolean | true |
customHolderRef | Ref of an element to use as a container for the dragged item | React.RefObject<HTMLElement | null> | document.body |
dropTarget | React element to use as a dropTarget | ReactNode | |
autoScroll | Determines whether the containing element (or window) should scroll during sort | boolean | false |
Note: onSortEnd is required.
The findItemIndexAtPosition function determines which item index corresponds to a specific coordinate { x, y } based on an array of DOMRect objects.
fallbackToClosest is set to true, and the point is not inside any rectangle, it returns the index of the rectangle whose center is closest to the point.fallbackToClosest is false (default) and the point is not inside any rectangle, it returns -1.import { findItemIndexAtPosition } from 'react-easy-sort';
const index = findItemIndexAtPosition(
{ x: 100, y: 150 },
itemsRects,
{ fallbackToClosest: true }
);The SortableList component accepts several props to control the sorting behavior and UI:
onSortEnd: (Required) Callback function called when a sorting gesture finishes. Receives (oldIndex: number, newIndex: number).onSortStart: Optional callback called when the user starts a sorting gesture.onSortMove: Optional callback called when an item's position changes during a gesture. Receives (newIndex: number).allowDrag: Boolean. Determines whether drag functionality is enabled (defaults to true).as: Determines the HTML tag used for the container element (defaults to 'div').draggedItemClassName: A string of CSS classes applied to the cloned element being dragged.lockAxis: 'x' | 'y'. Locks the drag movement to a specific axis.autoScroll: Boolean. Enables automatic scrolling of the container or window when dragging near edges (defaults to false).customHolderRef: A React.RefObject<HTMLElement | null> pointing to the element where the dragged clone should be appended (defaults to document.body).dropTarget: A React.ReactNode used as a drop target during dragging.SortableList also accepts all standard HTMLAttributes for the chosen tag.
The getScrollableParent function traverses up the DOM tree starting from a given HTMLElement to find the first ancestor that is scrollable (either horizontally or vertically).
overflowX or overflowY values of 'auto' or 'scroll' combined with dimension checks (scrollWidth > clientWidth or scrollHeight > clientHeight).window object.import { getScrollableParent } from 'react-easy-sort';
const scrollParent = getScrollableParent(myElement);The arrayMove function creates a new array with an item moved from one index to another. It performs a non-mutating operation by spreading the original array before moving the item.
array: The source array.fromIndex: The index of the item to move.toIndex: The destination index.Returns a new array instance.
import { arrayMove } from 'react-easy-sort';
const original = [1, 2, 3, 4];
const moved = arrayMove(original, 0, 2); // [2, 3, 1, 4]The SortableItem component is used to register a child element as a sortable item within a SortableList. It works by cloning its child and attaching a ref to it so the parent list can track its position.
Note: SortableItem must be a child of SortableList.