0
# Sortable Container
1
2
Higher-order component that transforms any React component into a container capable of holding sortable elements. Provides comprehensive configuration for drag behavior, animations, constraints, and event handling.
3
4
## Capabilities
5
6
### SortableContainer HOC
7
8
Creates a sortable container from any React component.
9
10
```typescript { .api }
11
/**
12
* Higher-order component that makes a component capable of containing sortable elements
13
* @param wrappedComponent - The React component to enhance with sortable functionality
14
* @param config - Optional configuration object
15
* @returns Enhanced React component with sortable container capabilities
16
*/
17
function SortableContainer<P>(
18
wrappedComponent: WrappedComponent<P>,
19
config?: Config
20
): React.ComponentClass<P & SortableContainerProps>;
21
22
interface Config {
23
withRef: boolean;
24
}
25
26
interface SortableContainerProps {
27
// Sorting Direction & Constraints
28
axis?: Axis;
29
lockAxis?: Axis;
30
lockToContainerEdges?: boolean;
31
lockOffset?: Offset | [Offset, Offset];
32
33
// Animation & Visual
34
helperClass?: string;
35
transitionDuration?: number;
36
keyboardSortingTransitionDuration?: number;
37
hideSortableGhost?: boolean;
38
39
// Trigger Behavior
40
pressDelay?: number;
41
pressThreshold?: number;
42
distance?: number;
43
useDragHandle?: boolean;
44
45
// Event Handlers
46
shouldCancelStart?: (event: SortEvent | SortEventWithTag) => boolean;
47
updateBeforeSortStart?: SortStartHandler;
48
onSortStart?: SortStartHandler;
49
onSortMove?: SortMoveHandler;
50
onSortEnd?: SortEndHandler;
51
onSortOver?: SortOverHandler;
52
53
// Scrolling & Container
54
useWindowAsScrollContainer?: boolean;
55
disableAutoscroll?: boolean;
56
getContainer?: ContainerGetter;
57
helperContainer?: HTMLElement | HelperContainerGetter;
58
getHelperDimensions?: (sort: SortStart) => Dimensions;
59
60
// Keyboard Navigation
61
keyCodes?: KeyCodes;
62
}
63
64
interface KeyCodes {
65
lift?: number[];
66
drop?: number[];
67
cancel?: number[];
68
up?: number[];
69
down?: number[];
70
}
71
```
72
73
**Usage Examples:**
74
75
```typescript
76
import React from 'react';
77
import { SortableContainer, SortableElement } from 'react-sortable-hoc';
78
79
// Basic sortable list
80
const SortableList = SortableContainer(({ items }) => {
81
return (
82
<ul>
83
{items.map((value, index) => (
84
<SortableItem key={`item-${value}`} index={index} value={value} />
85
))}
86
</ul>
87
);
88
});
89
90
// With configuration options
91
const AdvancedSortableList = SortableContainer(({ items }) => (
92
<div className="grid">
93
{items.map((item, index) => (
94
<SortableGridItem key={item.id} index={index} item={item} />
95
))}
96
</div>
97
));
98
99
// Usage with props
100
<AdvancedSortableList
101
items={items}
102
axis="xy"
103
helperClass="sortable-helper"
104
transitionDuration={200}
105
pressDelay={100}
106
onSortEnd={handleSortEnd}
107
useDragHandle={true}
108
/>
109
```
110
111
### Core Configuration Props
112
113
#### Sorting Direction
114
115
```typescript { .api }
116
/** Items can be sorted horizontally, vertically or in a grid */
117
axis?: 'x' | 'y' | 'xy'; // default: 'y'
118
119
/** Lock movement to an axis while sorting */
120
lockAxis?: 'x' | 'y';
121
```
122
123
#### Animation & Visual Props
124
125
```typescript { .api }
126
/** CSS class to add to the sortable helper element */
127
helperClass?: string;
128
129
/** Duration of transition when elements shift positions (ms) */
130
transitionDuration?: number; // default: 300
131
132
/** Duration for keyboard sorting transitions (ms) */
133
keyboardSortingTransitionDuration?: number; // defaults to transitionDuration
134
135
/** Whether to auto-hide the element being sorted */
136
hideSortableGhost?: boolean; // default: true
137
```
138
139
#### Trigger Behavior Props
140
141
```typescript { .api }
142
/** Time to wait before sorting begins (ms) - good for mobile */
143
pressDelay?: number; // default: 0
144
145
/** Pixels of movement to tolerate before ignoring press event */
146
pressThreshold?: number; // default: 5
147
148
/** Distance to drag before sorting begins (pixels) */
149
distance?: number; // default: 0
150
151
/** Whether to use drag handles for sorting */
152
useDragHandle?: boolean; // default: false
153
```
154
155
### Event Handler Props
156
157
#### Core Event Handlers
158
159
```typescript { .api }
160
/** Function to determine if sorting should be cancelled */
161
shouldCancelStart?: (event: SortEvent | SortEventWithTag) => boolean;
162
163
/** Async function called before sorting begins */
164
updateBeforeSortStart?: SortStartHandler;
165
166
/** Callback when sorting begins */
167
onSortStart?: SortStartHandler;
168
169
/** Callback during sorting as cursor moves */
170
onSortMove?: SortMoveHandler;
171
172
/** Callback when moving over an item */
173
onSortOver?: SortOverHandler;
174
175
/** Callback when sorting ends */
176
onSortEnd?: SortEndHandler;
177
```
178
179
**Event Handler Examples:**
180
181
```typescript
182
const handleSortStart = ({ node, index, collection, isKeySorting }, event) => {
183
console.log('Sorting started:', { index, collection, isKeySorting });
184
};
185
186
const handleSortEnd = ({ oldIndex, newIndex, collection, isKeySorting }, event) => {
187
if (oldIndex !== newIndex) {
188
const newItems = arrayMove(items, oldIndex, newIndex);
189
setItems(newItems);
190
}
191
};
192
193
const shouldCancel = (event) => {
194
// Don't sort if clicking on buttons or inputs
195
return ['INPUT', 'BUTTON', 'SELECT'].includes(event.target.tagName);
196
};
197
198
<SortableList
199
items={items}
200
onSortStart={handleSortStart}
201
onSortEnd={handleSortEnd}
202
shouldCancelStart={shouldCancel}
203
/>
204
```
205
206
### Advanced Configuration Props
207
208
#### Container & Scrolling
209
210
```typescript { .api }
211
/** Use window as the scrolling container */
212
useWindowAsScrollContainer?: boolean; // default: false
213
214
/** Disable autoscrolling while dragging */
215
disableAutoscroll?: boolean; // default: false
216
217
/** Function to return the scrollable container element */
218
getContainer?: ContainerGetter;
219
220
/** Container for the sortable helper element */
221
helperContainer?: HTMLElement | HelperContainerGetter; // default: document.body
222
223
/** Function to compute helper dimensions */
224
getHelperDimensions?: (sort: SortStart) => Dimensions;
225
```
226
227
#### Constraint Props
228
229
```typescript { .api }
230
/** Lock movement to container edges */
231
lockToContainerEdges?: boolean; // default: false
232
233
/** Offset distance from container edges when locked */
234
lockOffset?: Offset | [Offset, Offset]; // default: '50%'
235
```
236
237
**Constraint Examples:**
238
239
```typescript
240
// Lock to container with 10px margins
241
<SortableList
242
items={items}
243
lockToContainerEdges={true}
244
lockOffset="10px"
245
onSortEnd={handleSortEnd}
246
/>
247
248
// Different lock offsets for top/bottom
249
<SortableList
250
items={items}
251
lockToContainerEdges={true}
252
lockOffset={["0%", "100%"]}
253
onSortEnd={handleSortEnd}
254
/>
255
```
256
257
### Keyboard Navigation
258
259
#### Key Code Configuration
260
261
```typescript { .api }
262
/** Keyboard navigation key codes */
263
keyCodes?: {
264
lift?: number[]; // default: [32] (SPACE)
265
drop?: number[]; // default: [32] (SPACE)
266
cancel?: number[]; // default: [27] (ESC)
267
up?: number[]; // default: [38, 37] (UP, LEFT)
268
down?: number[]; // default: [40, 39] (DOWN, RIGHT)
269
};
270
```
271
272
**Keyboard Navigation Example:**
273
274
```typescript
275
// Custom key bindings
276
<SortableList
277
items={items}
278
keyCodes={{
279
lift: [13, 32], // Enter or Space to lift
280
drop: [13, 32], // Enter or Space to drop
281
cancel: [27], // Escape to cancel
282
up: [38, 87], // Up arrow or W
283
down: [40, 83], // Down arrow or S
284
}}
285
onSortEnd={handleSortEnd}
286
/>
287
```
288
289
## withRef Configuration
290
291
```typescript { .api }
292
interface Config {
293
/** Enable access to wrapped component instance */
294
withRef: boolean;
295
}
296
```
297
298
**withRef Example:**
299
300
```typescript
301
const SortableList = SortableContainer(ListComponent, { withRef: true });
302
303
// Access wrapped instance
304
const listRef = useRef();
305
const wrappedInstance = listRef.current?.getWrappedInstance();
306
307
<SortableList ref={listRef} items={items} onSortEnd={handleSortEnd} />
308
```
309
310
## SortableContext
311
312
React context that provides access to the internal sortable manager. Primarily used for advanced integrations and custom components.
313
314
```typescript { .api }
315
/**
316
* React context providing access to sortable manager
317
*/
318
const SortableContext: React.Context<{
319
manager: Manager;
320
}>;
321
```
322
323
**Usage Examples:**
324
325
```typescript
326
import React, { useContext } from 'react';
327
import { SortableContext } from 'react-sortable-hoc';
328
329
// Access sortable manager from context
330
const CustomSortableComponent = () => {
331
const { manager } = useContext(SortableContext);
332
333
// Use manager for advanced operations
334
const handleCustomAction = () => {
335
console.log('Sortable elements:', manager.refs);
336
};
337
338
return (
339
<div onClick={handleCustomAction}>
340
Custom sortable component
341
</div>
342
);
343
};
344
345
// Use within SortableContainer
346
const SortableList = SortableContainer(({ items }) => (
347
<ul>
348
{items.map((value, index) => (
349
<SortableItem key={`item-${index}`} index={index} value={value} />
350
))}
351
<CustomSortableComponent />
352
</ul>
353
));
354
```
355
356
**Note:** SortableContext is an advanced API primarily intended for library authors and complex integrations. Most applications should use the standard SortableContainer, SortableElement, and SortableHandle components.