react-native-drax

March 23, 2026 ยท View on GitHub

React Native CLI Expo CLI platforms GitHub top language CI GitHub license npm version

๐Ÿ“š Visit the official documentation

๐ŸŽฎ See the live example

๐Ÿ“– Overview

Drax is a declarative drag-and-drop framework for React Native, written in TypeScript. It supports free-form drag-and-drop, sortable lists and grids, cross-list reorder, drag handles, collision algorithms, and more.

Built on Reanimated 4 and Gesture Handler 3 with a UI-thread-first architecture for smooth 60fps interactions.

Platforms: iOS, Android, Web

โœจ Highlights

  • ๐Ÿ“‹ List-agnostic sortable โ€” works with FlatList, FlashList, LegendList, or any list component
  • ๐Ÿ”€ Cross-container drag โ€” move items between lists (cross-list reorder)
  • โšก UI-thread hit-testing โ€” spatial index worklet for fast receiver detection
  • โœŠ Drag handles โ€” only the handle starts a drag, the rest scrolls
  • ๐Ÿ’ฅ Collision algorithms โ€” center, intersect, or contain
  • ๐Ÿ“ Drag bounds โ€” constrain drags within a view
  • ๐ŸŽจ Hover styles โ€” conditional styles based on drag phase and receiver state
  • ๐Ÿšซ Drop zone acceptance โ€” accept or reject drops with acceptsDrag
  • ๐ŸŽฌ Animation presets โ€” default, spring, gentle, snappy, none โ€” or custom config
  • ๐Ÿงฒ Snap alignment โ€” snap to 9-point alignment within receivers
  • โ™ฟ Accessibility โ€” auto-generated labels, reduced motion support
  • ๐Ÿ“ก 19 callback events โ€” full drag lifecycle control
  • ๐Ÿ—๏ธ New Architecture compatible (Fabric)

๐Ÿค” Why Drax?

FeatureDraxreanimated-dndsortables
Free-form drag & dropโœ…โœ…โž–
Sortable list / gridโœ…โœ…โœ…
Mixed-size grid (non-uniform spans)โœ…โž–โž–
Cross-container / cross-list reorderโš ๏ธ Experimentalโž–โž–
List-agnostic (FlatList, FlashList, LegendList)โœ…โž–โž–
Drag handlesโœ…โœ…โœ…
Drag state styling15 props + inactiveonStateChange5 props + hook
Drop indicatorโœ…โž–Grid only
UI-thread DnD collisionโœ…โž–โž–
Event callbacks19 types~12 types~10 types
Accessibility + reduced motionโœ…ManualManual
Web supportโœ…โž–Partial
Reanimatedโ‰ฅ 4โ‰ฅ 4.2โ‰ฅ 3
Gesture Handlerโ‰ฅ 2โ‰ฅ 2.28โ‰ฅ 2

See full comparison โ†’

๐Ÿ“ฆ Installation

npm install react-native-drax
# or
yarn add react-native-drax

๐Ÿ”— Peer Dependencies

npm install react-native-reanimated react-native-gesture-handler
Peer DependencyVersion
react>= 18
react-native>= 0.68
react-native-reanimated^4.0.0
react-native-gesture-handler>= 2.0.0 (v3 recommended)

๐Ÿš€ Quick Start

๐Ÿ‘‹ Basic Drag-and-Drop

import { DraxProvider, DraxView } from 'react-native-drax';

function App() {
  return (
    <DraxProvider>
      <DraxView
        style={{ width: 100, height: 100, backgroundColor: 'blue' }}
        onDragStart={() => console.log('dragging')}
        payload="hello"
      />
      <DraxView
        style={{ width: 100, height: 100, backgroundColor: 'green' }}
        onReceiveDragDrop={({ dragged: { payload } }) => {
          console.log(`received: ${payload}`);
        }}
      />
    </DraxProvider>
  );
}

๐Ÿ“‹ Sortable List

The simplest way to make a reorderable list:

import { useState } from 'react';
import { Text, View } from 'react-native';
import { DraxProvider, DraxList } from 'react-native-drax';

function App() {
  const [items, setItems] = useState(['A', 'B', 'C', 'D', 'E']);

  return (
    <DraxProvider>
      <DraxList
        data={items}
        keyExtractor={(item) => item}
        onReorder={({ data }) => setItems(data)}
        renderItem={({ item }) => (
          <View style={{ padding: 16, backgroundColor: '#eee', margin: 4 }}>
            <Text>{item}</Text>
          </View>
        )}
      />
    </DraxProvider>
  );
}

DraxList is list-agnostic โ€” pass any list component via the component prop:

import { FlashList } from '@shopify/flash-list';

<DraxList
  component={FlashList}
  data={items}
  keyExtractor={(item) => item.id}
  onReorder={({ data }) => setItems(data)}
  renderItem={({ item }) => <ItemCard item={item} />}
  estimatedItemSize={60}
/>

๐Ÿงฑ Composable API

For full control, use the composable primitives directly:

import {
  DraxProvider,
  useSortableList,
  SortableContainer,
  SortableItem,
} from 'react-native-drax';
import { FlatList } from 'react-native';

function App() {
  const [items, setItems] = useState(['A', 'B', 'C', 'D', 'E']);
  const listRef = useRef<FlatList>(null);

  const sortable = useSortableList({
    data: items,
    keyExtractor: (item) => item,
    onReorder: ({ data }) => setItems(data),
  });

  return (
    <DraxProvider>
      <SortableContainer sortable={sortable} scrollRef={listRef}>
        <FlatList
          ref={listRef}
          data={sortable.data}
          keyExtractor={sortable.stableKeyExtractor}
          onScroll={sortable.onScroll}
          onContentSizeChange={sortable.onContentSizeChange}
          renderItem={({ item, index }) => (
            <SortableItem sortable={sortable} index={index}>
              <Text>{item}</Text>
            </SortableItem>
          )}
        />
      </SortableContainer>
    </DraxProvider>
  );
}

This pattern works with any list component โ€” FlatList, FlashList, LegendList, ScrollView, etc.

๐ŸŽ› Features

โœŠ Drag Handles

Only the handle area starts a drag โ€” the rest of the view scrolls normally:

import { DraxView, DraxHandle } from 'react-native-drax';

<DraxView dragHandle>
  <Text>This content scrolls normally</Text>
  <DraxHandle>
    <GripIcon />  {/* Only this starts a drag */}
  </DraxHandle>
</DraxView>

๐Ÿ“ Drag Bounds

Constrain a dragged view within a boundary:

const boundsRef = useRef<View>(null);

<View ref={boundsRef} style={{ flex: 1 }}>
  <DraxView dragBoundsRef={boundsRef}>
    <Text>I can only be dragged within the parent</Text>
  </DraxView>
</View>

๐Ÿ’ฅ Collision Algorithms

Control how receiver detection works:

<DraxView collisionAlgorithm="center" />   {/* hover center inside receiver (default) */}
<DraxView collisionAlgorithm="intersect" /> {/* any overlap triggers receiving */}
<DraxView collisionAlgorithm="contain" />   {/* dragged view must be fully inside */}

๐Ÿšซ Drop Zone Acceptance

Accept or reject drops conditionally:

<DraxView
  acceptsDrag={(draggedPayload) => items.length < 5}
  onReceiveDragDrop={({ dragged }) => addItem(dragged.payload)}
/>

๐ŸŽจ Hover Styles

Style the hover layer based on drag state:

<DraxView
  hoverStyle={{ opacity: 0.8 }}
  hoverDraggingWithReceiverStyle={{ borderColor: 'green', borderWidth: 2 }}
  hoverDraggingWithoutReceiverStyle={{ opacity: 0.5 }}
  hoverDragReleasedStyle={{ opacity: 0.3 }}
/>

๐Ÿงฒ Snap Alignment

Snap dropped items to specific positions within a receiver:

import { snapToAlignment } from 'react-native-drax';

<DraxView
  onReceiveDragDrop={({ dragged, receiver }) =>
    snapToAlignment(receiver, dragged, 'top-left', { x: 8, y: 8 })
  }
/>

Alignments: center, top-left, top-center, top-right, center-left, center-right, bottom-left, bottom-center, bottom-right

๐ŸŽฌ Animation Presets

<DraxList animationConfig="spring" />  {/* spring physics */}
<DraxList animationConfig="gentle" />  {/* soft spring */}
<DraxList animationConfig="snappy" />  {/* fast spring */}
<DraxList animationConfig="none" />    {/* instant */}

{/* Or custom: */}
<DraxList animationConfig={{
  useSpring: true,
  springDamping: 15,
  springStiffness: 150,
  springMass: 1,
}} />

Device reduced motion settings are respected automatically.

๐Ÿ“ก Continuous Drag Callbacks

<DraxView
  onDrag={(data) => { /* fires every frame while dragging over empty space */ }}
  onDragOver={(data) => { /* fires every frame while over the same receiver */ }}
/>

๐Ÿ”€ Cross-Container Sortable (Experimental)

Move items between lists (cross-list reorder):

import {
  useSortableBoard,
  SortableBoardContainer,
  useSortableList,
  SortableContainer,
  SortableItem,
} from 'react-native-drax';

const board = useSortableBoard({
  onTransfer: ({ fromColumnId, toColumnId, fromIndex, toIndex, item }) => {
    // Move item between columns
  },
});

<SortableBoardContainer board={board}>
  {columns.map((column) => (
    <Column key={column.id} board={board} column={column} />
  ))}
</SortableBoardContainer>

Note: Cross-container drag is experimental. The API may change in future versions.

๐Ÿท๏ธ Namespace API

For convenience, all components are available under the Drax namespace:

import { Drax } from 'react-native-drax';

<Drax.Provider>
  <Drax.View draggable>
    <Drax.Handle><GripIcon /></Drax.Handle>
  </Drax.View>
</Drax.Provider>

๐Ÿงฉ Components

ComponentDescription
DraxProviderContext provider โ€” wrap your app's drag-and-drop area
DraxViewDraggable and/or receptive view with 19 callback events
DraxListList-agnostic sortable list (convenience wrapper)
DraxHandleDrag handle โ€” only this area starts a drag
DraxScrollViewScrollable container with auto-scroll during drag
SortableContainerMonitoring wrapper for composable sortable API
SortableItemPer-item wrapper with shift animation
SortableBoardContainerCross-container board coordinator (experimental)

๐Ÿช Hooks

HookDescription
useSortableListList-agnostic reorder state management
useSortableBoardCross-container board coordinator (experimental)
useDraxContextAccess the Drax context
useDraxIdGenerate a unique Drax view ID

๐Ÿ’ก Examples

The example/ directory contains an Expo Router app with 11 screens demonstrating all features:

ScreenFeatures shown
Color Drag & DropDrop acceptance, hover styles, snap alignment
Reorderable ListDraxList, animation presets, auto-scroll
Reorderable GridSortable grid with multi-column layout
Mixed-Size GridItems with different spans (1ร—1, 2ร—2, etc.) using getItemSpan and packGrid
Drag HandlesOnly the grip icon starts a drag
Drag BoundsConstrain drag within a view
Collision ModesCenter vs Intersect vs Contain
Cross-List ReorderFlashList + LegendList + FlatList cross-container drag (experimental)
Knight MovesChess knight drag puzzle
ScrollingDrag from scroll view to drop zone
Stress Test100 items in a sortable list

To run the example app:

cd example && yarn start

๐Ÿ”„ Migration from v0.x

v1.0.0 is a complete rewrite. Key changes:

  • DraxList is new โ€” list-agnostic convenience wrapper using the new sortable architecture. The old DraxList / DraxListItem API from v0.10.x and v0.11.0-alpha is removed.
  • New sortable architecture โ€” useSortableList + SortableContainer + SortableItem composable API replaces the old array-indexed approach.
  • Reanimated 4 + Gesture Handler 3 โ€” required peer dependencies (Gesture Handler v2 supported via compat layer with reduced performance).
  • New Architecture (Fabric) compatible.

๐Ÿ“‹ Changelog

See CHANGELOG.md for a full list of changes.

๐Ÿค Contributing

Issues, pull requests, and discussion are all welcome. See the Contribution Guidelines for details.

๐Ÿ“œ Code of Conduct

This project is released with a Contributor Code of Conduct. By participating in this project you agree to abide by its terms.

๐Ÿ† Contributors

Originally created by Joe Lafiosca. v1.0.0 rewrite led by Ovidiu Cristescu.

Thanks to all contributors who have helped make Drax better:

Joe Lafiosca
Joe Lafiosca

๐Ÿ’ป ๐Ÿ“– ๐Ÿ’ก ๐Ÿšง ๐Ÿš‡
Ovidiu Cristescu
Ovidiu Cristescu

๐Ÿ’ป ๐Ÿ“– ๐Ÿ’ก ๐Ÿšง
Franรงois Dupayrat
Franรงois Dupayrat

๐Ÿ’ป
Josh Arnold
Josh Arnold

๐Ÿ’ป
Rahul Nallappa
Rahul Nallappa

๐Ÿ’ป
negue
negue

๐Ÿ“–
Chris Drackett
Chris Drackett

๐Ÿ’ป
Matti Salokangas
Matti Salokangas

๐Ÿ’ป
Andres Garcia
Andres Garcia

๐Ÿ’ป

๐Ÿ“ƒ License

MIT


Built and maintained using OpenKit.