react-native-drax
March 23, 2026 ยท View on GitHub
๐ 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?
| Feature | Drax | reanimated-dnd | sortables |
|---|---|---|---|
| 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 styling | 15 props + inactive | onStateChange | 5 props + hook |
| Drop indicator | โ | โ | Grid only |
| UI-thread DnD collision | โ | โ | โ |
| Event callbacks | 19 types | ~12 types | ~10 types |
| Accessibility + reduced motion | โ | Manual | Manual |
| Web support | โ | โ | Partial |
| Reanimated | โฅ 4 | โฅ 4.2 | โฅ 3 |
| Gesture Handler | โฅ 2 | โฅ 2.28 | โฅ 2 |
๐ฆ Installation
npm install react-native-drax
# or
yarn add react-native-drax
๐ Peer Dependencies
npm install react-native-reanimated react-native-gesture-handler
| Peer Dependency | Version |
|---|---|
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
| Component | Description |
|---|---|
DraxProvider | Context provider โ wrap your app's drag-and-drop area |
DraxView | Draggable and/or receptive view with 19 callback events |
DraxList | List-agnostic sortable list (convenience wrapper) |
DraxHandle | Drag handle โ only this area starts a drag |
DraxScrollView | Scrollable container with auto-scroll during drag |
SortableContainer | Monitoring wrapper for composable sortable API |
SortableItem | Per-item wrapper with shift animation |
SortableBoardContainer | Cross-container board coordinator (experimental) |
๐ช Hooks
| Hook | Description |
|---|---|
useSortableList | List-agnostic reorder state management |
useSortableBoard | Cross-container board coordinator (experimental) |
useDraxContext | Access the Drax context |
useDraxId | Generate a unique Drax view ID |
๐ก Examples
The example/ directory contains an Expo Router app with 11 screens demonstrating all features:
| Screen | Features shown |
|---|---|
| Color Drag & Drop | Drop acceptance, hover styles, snap alignment |
| Reorderable List | DraxList, animation presets, auto-scroll |
| Reorderable Grid | Sortable grid with multi-column layout |
| Mixed-Size Grid | Items with different spans (1ร1, 2ร2, etc.) using getItemSpan and packGrid |
| Drag Handles | Only the grip icon starts a drag |
| Drag Bounds | Constrain drag within a view |
| Collision Modes | Center vs Intersect vs Contain |
| Cross-List Reorder | FlashList + LegendList + FlatList cross-container drag (experimental) |
| Knight Moves | Chess knight drag puzzle |
| Scrolling | Drag from scroll view to drop zone |
| Stress Test | 100 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:
DraxListis new โ list-agnostic convenience wrapper using the new sortable architecture. The oldDraxList/DraxListItemAPI from v0.10.x and v0.11.0-alpha is removed.- New sortable architecture โ
useSortableList+SortableContainer+SortableItemcomposable 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 ๐ป ๐ ๐ก ๐ง ๐ |
Ovidiu Cristescu ๐ป ๐ ๐ก ๐ง |
Franรงois Dupayrat ๐ป |
Josh Arnold ๐ป |
Rahul Nallappa ๐ป |
negue ๐ |
Chris Drackett ๐ป |
Matti Salokangas ๐ป |
Andres Garcia ๐ป |
๐ License
Built and maintained using OpenKit.