{"id":27787971,"url":"https://github.com/omahili/react-native-reorderable-list","last_synced_at":"2026-01-02T16:15:37.695Z","repository":{"id":40571726,"uuid":"435206467","full_name":"omahili/react-native-reorderable-list","owner":"omahili","description":"A reorderable list for React Native applications, powered by Reanimated 🚀","archived":false,"fork":false,"pushed_at":"2025-05-12T16:57:18.000Z","size":1649,"stargazers_count":246,"open_issues_count":8,"forks_count":13,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-05-12T17:59:29.897Z","etag":null,"topics":["dnd","drag-and-drop","drag-n-drop","flatlist","list","react","react-native","reanimated","reorderable","reorderable-list","sortable","sortable-list"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/omahili.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2021-12-05T15:34:46.000Z","updated_at":"2025-05-12T16:57:21.000Z","dependencies_parsed_at":"2025-01-26T20:21:26.407Z","dependency_job_id":"ae366072-0c7a-448f-b432-9263c9e67dcd","html_url":"https://github.com/omahili/react-native-reorderable-list","commit_stats":{"total_commits":22,"total_committers":3,"mean_commits":7.333333333333333,"dds":0.09090909090909094,"last_synced_commit":"8358ed846e17cf2a0b73259dc823793b4ef8cb4a"},"previous_names":[],"tags_count":17,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/omahili%2Freact-native-reorderable-list","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/omahili%2Freact-native-reorderable-list/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/omahili%2Freact-native-reorderable-list/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/omahili%2Freact-native-reorderable-list/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/omahili","download_url":"https://codeload.github.com/omahili/react-native-reorderable-list/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254364270,"owners_count":22058878,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["dnd","drag-and-drop","drag-n-drop","flatlist","list","react","react-native","reanimated","reorderable","reorderable-list","sortable","sortable-list"],"created_at":"2025-04-30T16:53:05.756Z","updated_at":"2026-01-02T16:15:37.689Z","avatar_url":"https://github.com/omahili.png","language":"TypeScript","funding_links":[],"categories":["Mobile"],"sub_categories":["React Native \u0026 Expo"],"readme":"[![NPM Downloads](https://img.shields.io/npm/dm/react-native-reorderable-list)](https://www.npmjs.com/package/react-native-reorderable-list)\n[![GitHub License](https://img.shields.io/github/license/omahili/react-native-reorderable-list)](https://github.com/omahili/react-native-reorderable-list?tab=MIT-1-ov-file#readme)\n[![NPM Version](https://img.shields.io/npm/v/react-native-reorderable-list)](https://www.npmjs.com/package/react-native-reorderable-list?activeTab=versions)\n\u003cbr /\u003e\n[![iOS](https://img.shields.io/badge/platform-iOS-000.svg?logo=apple)](https://developer.apple.com/ios)\n[![Android](https://img.shields.io/badge/platform-Android-3ddc84.svg?logo=android)](https://www.android.com)\n\n# React Native Reorderable List\n\nA reorderable list for React Native applications, powered by Reanimated 🚀.\n\n![Demo](https://media0.giphy.com/media/v1.Y2lkPTc5MGI3NjExanBuODMwN29scmxoNXY0MmZkcHpzZnFxYXE5eTVydzBsbHIyY3ZqMyZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/T9uQrEnUCijeJOzSs9/giphy.gif)\n\n### Features\n\n- Drag \u0026 Drop FlatList\n- Vertical \u0026 Horizontal Mode\n- Layout Animations\n- Nested Lists\n- Custom Animations\n- Drop Indicator\n\n## Index\n\n- [Install](#install)\n- [Components](#components)\n  - [ReorderableList](#reorderablelist)\n  - [ScrollViewContainer](#scrollviewcontainer)\n  - [NestedReorderableList](#nestedreorderablelist)\n- [Hooks](#hooks)\n  - [useReorderableDrag](#usereorderabledrag)\n  - [useReorderableDragStart](#usereorderabledragstart)\n  - [useReorderableDragEnd](#usereorderabledragend)\n  - [useIsActive](#useisactive)\n- [Utils](#utils)\n- [Troubleshooting](#troubleshooting)\n  - [Navigation Gestures](#navigation-gestures)\n  - [Refresh Control](#refresh-control)\n- [Example](#example)\n- [License](#license)\n\n## Install\n\n\u003e **NOTE**: This package follows [semantic versioning](https://semver.org/). Versions 0.X.0 are safe to use but may introduce breaking changes, as the public API is not considered stable yet.\n\nNpm:\n\n```bash\nnpm install --save react-native-reorderable-list\n```\n\nYarn:\n\n```bash\nyarn add react-native-reorderable-list\n```\n\nThen you need to install these two peer dependencies:\n\n- [React Native Reanimated](https://docs.swmansion.com/react-native-reanimated) \u003e=3.12.0\n- [React Native Gesture Handler](https://docs.swmansion.com/react-native-gesture-handler) \u003e=2.12.0\n\n## Components\n\n### ReorderableList\n\nThis component uses a [FlatList](https://reactnative.dev/docs/flatlist) and it extends its props:\n\n| Props                     | Type                                             | Required | Default                    | Description                                                                                                                                                                                                                                                                                                                                                                                                    |\n| ------------------------- | ------------------------------------------------ | -------- | -------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| renderDropIndicator                  | `ReorderableListRenderItem\u003cT\u003e`    | No       | N/A                        | A render function to customise the drop indicator, which shows where an item will be dropped. If not provided, no drop indicator will be displayed.                                                                                                                                                                          |\n| autoscrollThreshold       | `number`                                         | No       | `0.1`                      | Threshold at the extremity of the list that triggers autoscroll when an item is dragged to it. A value of `0.1` means that 10% of the area at the top and 10% at the bottom will trigger autoscroll. Min value: `0`. Max value: `0.4`.                                                                                                                                                                         |\n| autoscrollThresholdOffset | `{start?: number; end?: number}`                | No       | `{start: 0, end: 0}`      | Amount by which the threshold is offset at the extremety of the list. For example, setting `{start: 50}` will make the autoscroll trigger 50 pixels earlier at the start of the list.                                                                                                                                                                               |\n| autoscrollSpeedScale      | `number`                                         | No       | `1`                        | Scales the autoscroll speed at which the list scrolls when an item is dragged to the scroll areas.                                                                                                                                                                                                                                                                                                             |\n| autoscrollDelay           | `number`                                         | No       | `0` (Android), `100` (iOS) | Delay in between autoscroll triggers. Can be used to tune the autoscroll smoothness. Default values differ between platforms: `0` for Android and `100` for iOS.                                                                                                                                                                                                                                               |\n| autoscrollActivationDelta | `number`                                         | No       | `5`                        | Allows configuring the delta for autoscroll activation when dragging an item in the same direction as the autoscroll. This is particularly useful when an item is dragged within the autoscroll area to account for minor unintentional movements.                                                                                                                                                             |\n| animationDuration         | `number`                                         | No       | `200`                      | Duration of the animations in milliseconds. Users won't be able to drag a new item until the dragged item is released and its animation to its new position ends.                                                                                                                                                                                                                                              |\n| cellAnimations            | `ReorderableListCellAnimations`                  | No       | N/A                        | Allows passing an object with values and/or shared values that can animate a cell, for example by using the `onDragStart` and `onDragEnd` events. Supports view style properties. Override opacity and/or transform to disable the default animation, e.g. `{opacity: 1, transform: []}`. Check the [examples](https://github.com/omahili/react-native-reorderable-list/tree/master/example) for more details. |\n| itemLayoutAnimation            | `ComponentProps\u003ctypeof Animated.View\u003e['layout']`      | No       | N/A                        | Layout animation when the item is added to and/or removed from the view hierarchy. To skip entering or exiting animations use the LayoutAnimationConfig component from [Reanimated](https://docs.swmansion.com/react-native-reanimated). |\n|  dragEnabled           | `boolean`                  | No       | `true`                        | Whether dragging items is enabled. |\n| shouldUpdateActiveItem    | boolean                                          | No       | `false`                    | Whether the active item should be updated. Enables usage of `useIsActive` hook.                                                                                                                                                                                                                                                                                                                                |\n| panGesture                | `PanGesture`                                     | No       | N/A                        | Custom instance of pan gesture. See [GestureHandler docs](https://docs.swmansion.com/react-native-gesture-handler) for further info.                                                                                                                                                                                                                                                                           |\n| onReorder                 | `(event: ReorderableListReorderEvent) =\u003e void` | Yes      | N/A                        | Event fired after an item is released and the list is reordered.                                                                                                                                                                                                                                                                                                                                               |\n| onDragStart               | `(event: ReorderableListDragStartEvent) =\u003e void`             | No       | N/A                        | Event fired when an item is dragged. Needs to be a `worklet`. See [Reanimated docs](https://docs.swmansion.com/react-native-reanimated) for further info.                                                                                                                                                                                                                                                      |\n| onDragEnd                 | `(event: ReorderableListDragEndEvent) =\u003e void` | No       | N/A                        | Event fired when the dragged item is released. Needs to be a `worklet`. See [Reanimated docs](https://docs.swmansion.com/react-native-reanimated) for further info.                                                                                                                                                                                                                                            |\n| onIndexChange             | `(event: ReorderableListIndexChangeEvent) =\u003e void`             | No       | N/A                        | Event fired when the index of the dragged item changes. Needs to be a `worklet`. See [Reanimated docs](https://docs.swmansion.com/react-native-reanimated) for further info.                                                                                                                                                                                                                                   |\n| onScroll                  | `ReturnType\u003ctypeof useAnimatedScrollHandler\u003e`    | No       | N/A                        | An animated scroll handler created with useAnimatedScrollHandler. See [Reanimated docs](https://docs.swmansion.com/react-native-reanimated) for further info.                                                                                                                                                                                                                                                  |\n\nThe following props from FlatList are not supported:\n\n- scrollEventThrottle\n- removeClippedSubviews\n- CellRendererComponent\n- numColumns\n\n### ScrollViewContainer\n\nThis component extends the [ScrollView](https://reactnative.dev/docs/scrollview) component and is used for nesting a [NestedReorderableList](#nestedreorderablelist) within a scrollable container:\n\n| Props    | Type                                          | Required | Default | Description                                                                                                                                                   |\n| -------- | --------------------------------------------- | -------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| onScroll | `ReturnType\u003ctypeof useAnimatedScrollHandler\u003e` | No       | N/A     | An animated scroll handler created with useAnimatedScrollHandler. See [Reanimated docs](https://docs.swmansion.com/react-native-reanimated) for further info. |\n\n### NestedReorderableList\n\nThis component allows nesting a reorderable list within a [ScrollViewContainer](#scrollviewcontainer):\n\n| Props      | Type      | Required | Default | Description                                                                                                                                            |\n| ---------- | --------- | -------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |\n  | scrollable | `boolean` | No       | `false`   | Whether the nested list is scrollable or not. If the nested list has a fixed height and it's scrollable it should be set to `true`, otherwise `false`. |\n\n## Hooks\n\n### useReorderableDrag\n\nThis hook creates a function that triggers the drag of a list item. It's usually called on a long press event. This hook can only be used inside of a list item component.\n\n##### Returns\n\n- `() =\u003e void`\n\n### useReorderableDragStart\n\nThis hook allows handling the drag start event of a list item. This hook can only be used inside of a list item component. It receives a worklet callback that is called when the drag starts. It's recommended to wrap the handler function in a useCallback as follows:\n\n```typescript\nuseReorderableDragStart(\n  useCallback((index: number) =\u003e {\n    'worklet';\n\n    // ...\n  }, []),\n);\n```\n\nUsing this hook in large lists is discouraged due to performance bottlenecks, prefer `onDragStart` on the ReorderableList instead.\n\n### useReorderableDragEnd\n\nThis hook allows handling the drag end event of a list item. This hook can only be used inside of a list item component. It receives a worklet callback that is called when the drag starts. It's recommended to wrap the handler function in a useCallback as follows:\n\n```typescript\nuseReorderableDragEnd(\n  useCallback((from: number, to: number) =\u003e {\n    'worklet';\n\n    // ...\n  }, []),\n);\n```\n\nUsing this hook in large lists is discouraged due to performance bottlenecks, prefer `onDragEnd` on the ReorderableList instead.\n\n### useIsActive\n\nThis hook returns a boolean indicating whether the current item is active. It will return true on drag start and false on drag end. This hook can only be used inside of a list item component.\n\n```typescript\nconst isActive = useIsActive();\n```\n\nAdditionally this hook requires setting `shouldUpdateActiveItem` to true on the ReorderableList:\n\n```typescript\n\u003cReorderableList\n  // ...\n  shouldUpdateActiveItem\n/\u003e\n```\n\n## Utils\n\n- **reorderItems**: `\u003cT\u003e(data: T[], from: number, to: number) =\u003e T[]`\n\n  This function receives an array of items, the index of the item to be moved, and the index of the new position and it returns a new array with the items reordered.\n\n## Troubleshooting\n\n### Navigation Gestures\n\nIf you'd like to allow for gesture-based navigation, such as swiping to go back, there are several ways to do it when working with reorderable list. You can delay the activation of pan gestures necessary for dragging items by setting the `activateAfterLongPress` on pan gesture. This duration should be slightly longer than the long press delay necessary to drag your items. If you're using Pressable the `delayLongPress` is 500 ms by default.\n\n```typescript\nimport {Gesture} from 'react-native-gesture-handler';\n\nconst panGesture = useMemo(() =\u003e Gesture.Pan().activateAfterLongPress(520), []);\n\nreturn (\n  \u003cReorderableList\n    // ...\n    panGesture={panGesture}\n  /\u003e\n);\n```\n\nAnother solution is to set a bigger activation offset on the x axis:\n\n```typescript\nimport {Gesture} from 'react-native-gesture-handler';\n\n// If it doesn't work try with bigger values.\nconst panGesture = useMemo(\n  () =\u003e Gesture.Pan().activeOffsetX([-20, 20]).activeOffsetY([0, 0]),\n  [],\n);\n\nreturn (\n  \u003cReorderableList\n    // ...\n    panGesture={panGesture}\n  /\u003e\n);\n```\n\nOne more way is to set a negative hit slop, however keep in mind that this will disable drag starts from the sides of your reorderable items:\n\n```typescript\nimport {Gesture} from 'react-native-gesture-handler';\n\n// If it doesn't work try with bigger values.\nconst panGesture = useMemo(() =\u003e Gesture.Pan().hitSlop(-10), []);\n\nreturn (\n  \u003cReorderableList\n    // ...\n    panGesture={panGesture}\n  /\u003e\n);\n```\n\n### Refresh Control\n\nIf you want to use RefreshControl with ReorderableList you might encounter some issues on Android, where gestures are conflicting making one or both of the components non responsive. To overcome this issues you can delay the activation of pan gestures necessary for dragging items by setting the `activateAfterLongPress` on pan gesture. This duration should be slightly longer than the long press delay necessary to drag your items. If you're using Pressable the `delayLongPress` is 500 ms by default.\n\n```typescript\nimport {Gesture} from 'react-native-gesture-handler';\n\nconst panGesture = useMemo(() =\u003e Gesture.Pan().activateAfterLongPress(520), []);\n\nreturn (\n  \u003cReorderableList\n    // ...\n    panGesture={panGesture}\n  /\u003e\n);\n```\n\nIf you change `delayLongPress` on your Pressable, update this prop accordingly.\n\nAnother issue you'll encounter is that when you drag your items the RefreshControl might animate. To avoid this you can enable and disable it on drag start and drag end like so:\n\n```typescript\nconst [refreshEnabled, setRefreshEnabled] = useState(true);\n\nconst handleDragStart = useCallback(() =\u003e {\n  'worklet';\n\n  // NOTE: If it's refreshing we don't want the refresh control to disappear\n  // and we can keep it enabled since it won't conflict with the drag.\n  if (Platform.OS === 'android' \u0026\u0026 !refreshing) {\n    runOnJS(setRefreshEnabled)(false);\n  }\n}, [refreshing]);\n\nconst handleDragEnd = useCallback(() =\u003e {\n  'worklet';\n\n  if (Platform.OS === 'android') {\n    runOnJS(setRefreshEnabled)(true);\n  }\n}, []);\n\nreturn (\n  \u003cReorderableList\n    // ...\n    onDragStart={handleDragStart}\n    onDragEnd={handleDragEnd}\n    refreshControl={\n      \u003cRefreshControl\n        // ...\n        enabled={refreshEnabled}\n      /\u003e\n    }\n  /\u003e\n);\n```\n\n## Example\n\nHere is simple example of how to use this component. Examples of nested lists and much more can be found in the [example](https://github.com/omahili/react-native-reorderable-list/tree/master/example) directory.\n\n```typescript\nimport React, {memo, useState} from 'react';\nimport {ListRenderItemInfo, Pressable, StyleSheet, Text} from 'react-native';\n\nimport ReorderableList, {\n  ReorderableListReorderEvent,\n  reorderItems,\n  useReorderableDrag,\n} from 'react-native-reorderable-list';\n\ninterface CardProps {\n  id: string;\n  color: string;\n  height: number;\n}\n\nconst rand = () =\u003e Math.floor(Math.random() * 256);\n\nconst seedData: CardProps[] = Array(20)\n  .fill(null)\n  .map((_, i) =\u003e ({\n    id: i.toString(),\n    color: `rgb(${rand()}, ${rand()}, ${rand()})`,\n    height: Math.max(60, Math.floor(Math.random() * 100)),\n  }));\n\nconst Card: React.FC\u003cCardProps\u003e = memo(({id, color, height}) =\u003e {\n  const drag = useReorderableDrag();\n\n  return (\n    \u003cPressable style={[styles.card, {height}]} onLongPress={drag}\u003e\n      \u003cText style={[styles.text, {color}]}\u003eCard {id}\u003c/Text\u003e\n    \u003c/Pressable\u003e\n  );\n});\n\nconst Example = () =\u003e {\n  const [data, setData] = useState(seedData);\n\n  const handleReorder = ({from, to}: ReorderableListReorderEvent) =\u003e {\n    setData(value =\u003e reorderItems(value, from, to));\n  };\n\n  const renderItem = ({item}: ListRenderItemInfo\u003cCardProps\u003e) =\u003e (\n    \u003cCard {...item} /\u003e\n  );\n\n  return (\n    \u003cReorderableList\n      data={data}\n      onReorder={handleReorder}\n      renderItem={renderItem}\n      // IMPORTANT: Do not use the current index as key.\n      // Always use a stable and unique key for each item.\n      keyExtractor={item =\u003e item.id}\n    /\u003e\n  );\n};\n\nconst styles = StyleSheet.create({\n  card: {\n    justifyContent: 'center',\n    alignItems: 'center',\n    backgroundColor: 'white',\n    borderBottomWidth: 1,\n    borderBottomColor: '#ddd',\n  },\n  text: {\n    fontSize: 20,\n  },\n});\n\nexport default Example;\n```\n\n## License\n\nMIT\n\n---\n\nMade with [create-react-native-library](https://github.com/callstack/react-native-builder-bob)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fomahili%2Freact-native-reorderable-list","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fomahili%2Freact-native-reorderable-list","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fomahili%2Freact-native-reorderable-list/lists"}