react-easy-sort

repository·main·Indexed 41 days ago

https://github.com/valentinh/react-easy-sort

A 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.

Tokens
2.7K
Snippets
8
Records
14
Agent score
51%

What's inside react-easy-sort

  1. Recommended CSS for sortable items

    main

    To 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.
  2. Use SortableList, SortableItem, and SortableKnob to create a sortable list

    main

    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>
  3. Basic usage of react-easy-sort

    main

    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>
      )
    }
  4. Use SortableKnob for partial item dragging

    main

    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>
      )
    }
  5. SortableItem requirements

    main
    The 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().
  6. SortableList Props Reference

    main

    The SortableList component accepts the following props:

    NameDescriptionTypeDefault
    asDetermines html tag for the container elementkeyof JSX.IntrinsicElementsdiv
    onSortStartCalled when the user starts a sorting gesture() => void-
    onSortMoveCalled 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-
    draggedItemClassNameClass applied to the item being draggedstring-
    lockAxisDetermines if an axis should be locked'x' | 'y'
    allowDragDetermines whether items can be draggedbooleantrue
    customHolderRefRef of an element to use as a container for the dragged itemReact.RefObject<HTMLElement | null>document.body
    dropTargetReact element to use as a dropTargetReactNode
    autoScrollDetermines whether the containing element (or window) should scroll during sortbooleanfalse

    Note: onSortEnd is required.

  7. Find item index at position with findItemIndexAtPosition

    main

    The findItemIndexAtPosition function determines which item index corresponds to a specific coordinate { x, y } based on an array of DOMRect objects.

    • If the point is inside a rectangle, it returns that index immediately.
    • If 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.
    • If 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 }
    );
  8. Configure SortableList props

    main

    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.

  9. Get the scrollable parent with getScrollableParent

    main

    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).

    • It checks for overflowX or overflowY values of 'auto' or 'scroll' combined with dimension checks (scrollWidth > clientWidth or scrollHeight > clientHeight).
    • If no scrollable parent is found, it returns the window object.
    import { getScrollableParent } from 'react-easy-sort';
    
    const scrollParent = getScrollableParent(myElement);
  10. Move items in an array with arrayMove

    main

    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]
  11. SortableItem component

    main

    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.