npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, πŸ‘‹, I’m Ryan HefnerΒ  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you πŸ™

Β© 2026 – Pkg Stats / Ryan Hefner

react-native-draggable-order-list

v1.0.3

Published

πŸš€ A truly flicker-free, high-performance Draggable FlatList for React Native. Built with Reanimated 4 & Worklets for native UI thread speed. ⚑

Readme

react-native-draggable-order-list

πŸš€ A truly flicker-free, high-performance Draggable FlatList for React Native. Built with Reanimated 4 & Worklets for native UI thread speed. ⚑

| NPM Downloads | GitHub Stars | License | | :--- | :--- | :--- | | ![npm downloads badge] | ![GitHub stars badge] | MIT License |

✨ Why Choose react-native-draggable-order-list?

This library eliminates the performance bottleneck common in other solutions by never updating React state during a drag. The result is a smooth, 60fps native feel, even when dragging items in lists of thousands.

  • Native UI Thread Animation: All item movement, scaling, and index-swapping calculations are handled by Reanimated Worklets, bypassing the JavaScript bridge.
  • Variable Height Support: Accurately calculates swap zones based on the actual measured height of each item.
  • Auto-Scrolling: Built-in logic to auto-scroll the list when the dragged item hits the viewport edges.
  • Zero Flicker: Items never fade or flicker during reordering thanks to optimized layout animations.

πŸ“¦ Installation

This library requires react-native-reanimated (v4+) and react-native-gesture-handler.

npm install react-native-draggable-order-list react-native-reanimated react-native-gesture-handler react-native-worklets
# or
yarn add react-native-draggable-order-list react-native-reanimated react-native-gesture-handler react-native-worklets

Additional Setup

Make sure to complete the setup for the peer dependencies:

  1. React Native Reanimated: Follow the official setup guide
  2. React Native Gesture Handler: Follow the official setup guide

πŸš€ Quick Start

Here's a basic example to get you started:

import React, { useRef, useState } from 'react';
import { View, Text, TouchableOpacity, StyleSheet } from 'react-native';
import DraggableList, { DraggableListRef, TItem } from 'react-native-draggable-order-list';

interface Task extends TItem {
  id: number;
  text: string;
}

const initialData: Task[] = [
  { id: 1, text: 'First Task' },
  { id: 2, text: 'Second Task' },
  { id: 3, text: 'Third Task' },
];

export default function App() {
  const [data, setData] = useState(initialData);
  const listRef = useRef<DraggableListRef<Task>>(null);

  const handleSaveOrder = () => {
    const finalOrder = listRef.current?.getCurrentData();
    if (finalOrder) {
      setData(finalOrder);
      console.log('Final Order:', finalOrder);
      // Send to your API or Redux store
    }
  };

  return (
    <View style={styles.container}>
      <DraggableList<Task>
        ref={listRef}
        data={data}
        renderItem={(item, isDragging) => (
          <View
            style={[
              styles.item,
              isDragging && styles.itemDragging,
            ]}
          >
            <Text style={styles.itemText}>{item.text}</Text>
          </View>
        )}
        keyExtractor={(item) => String(item.id)}
      />
      
      <TouchableOpacity onPress={handleSaveOrder} style={styles.saveButton}>
        <Text style={styles.saveButtonText}>Save Order</Text>
      </TouchableOpacity>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    padding: 20,
  },
  item: {
    height: 60,
    backgroundColor: 'white',
    padding: 15,
    marginVertical: 4,
    borderWidth: 1,
    borderColor: '#ccc',
    borderRadius: 8,
  },
  itemDragging: {
    backgroundColor: '#e0e0ff',
    borderColor: '#4a4ae7',
    elevation: 5,
    shadowColor: '#000',
    shadowOffset: { width: 0, height: 2 },
    shadowOpacity: 0.25,
    shadowRadius: 3.84,
  },
  itemText: {
    fontSize: 16,
  },
  saveButton: {
    padding: 15,
    backgroundColor: '#4a4ae7',
    borderRadius: 8,
    marginTop: 10,
  },
  saveButtonText: {
    color: 'white',
    textAlign: 'center',
    fontSize: 16,
    fontWeight: 'bold',
  },
});

πŸ“š Examples

Example 1: Variable Height Items

The library automatically handles items with different heights:

interface Note extends TItem {
  id: number;
  title: string;
  content: string;
}

const notes: Note[] = [
  { id: 1, title: 'Short Note', content: 'Brief content' },
  { id: 2, title: 'Long Note', content: 'This is a much longer note with more content...' },
];

<DraggableList<Note>
  data={notes}
  renderItem={(item, isDragging) => (
    <View style={[styles.note, isDragging && styles.noteDragging]}>
      <Text style={styles.noteTitle}>{item.title}</Text>
      <Text style={styles.noteContent}>{item.content}</Text>
    </View>
  )}
  keyExtractor={(item) => String(item.id)}
/>

Example 2: Custom Drag Handle

Add a dedicated drag handle instead of making the entire item draggable:

import { GestureDetector, Gesture } from 'react-native-gesture-handler';

<DraggableList<Task>
  data={data}
  renderItem={(item, isDragging) => {
    const panGesture = Gesture.Pan()
      .onStart(() => {
        // Trigger drag start
      });

    return (
      <View style={styles.itemContainer}>
        <View style={styles.itemContent}>
          <Text>{item.text}</Text>
        </View>
        <GestureDetector gesture={panGesture}>
          <View style={styles.dragHandle}>
            <Text>☰</Text>
          </View>
        </GestureDetector>
      </View>
    );
  }}
  keyExtractor={(item) => String(item.id)}
/>

Example 3: Custom Auto-Scroll Speed

Adjust the auto-scroll speed for better UX:

<DraggableList<Task>
  data={data}
  renderItem={(item, isDragging) => <YourItem item={item} isDragging={isDragging} />}
  keyExtractor={(item) => String(item.id)}
  autoScrollSpeed={12} // Default is 8
/>

Example 4: Custom Content Container Style

Apply custom styles to the list container:

<DraggableList<Task>
  data={data}
  renderItem={(item, isDragging) => <YourItem item={item} isDragging={isDragging} />}
  keyExtractor={(item) => String(item.id)}
  contentContainerStyle={{
    paddingHorizontal: 16,
    paddingBottom: 100,
  }}
/>

πŸ“– API Reference

DraggableList Props

| Prop | Type | Required | Default | Description | |------|------|----------|---------|-------------| | data | T[] | βœ… | - | Array of items to render. Each item must extend TItem (have an id field) | | renderItem | (item: T, isDragging: boolean) => ReactNode | βœ… | - | Function to render each item. Receives the item and dragging state | | keyExtractor | (item: T) => string | βœ… | - | Function to extract unique key from each item | | contentContainerStyle | ViewStyle | ❌ | - | Style for the FlatList content container | | autoScrollSpeed | number | ❌ | 8 | Speed of auto-scrolling when dragging near edges |

DraggableListRef Methods

Access these methods via ref:

const listRef = useRef<DraggableListRef<YourItemType>>(null);

// Get current order without triggering re-render
const currentOrder = listRef.current?.getCurrentData();

| Method | Returns | Description | |--------|---------|-------------| | getCurrentData() | T[] | Returns the current order of items after drag operations |

TItem Interface

Your data items must extend this interface:

interface TItem {
  id: string | number;  // Required: unique identifier
  [key: string]: any;   // Any additional properties
}

🎯 Best Practices

1. Use useCallback for renderItem

Memoize your render function to prevent unnecessary re-renders:

const renderItem = useCallback((item: Task, isDragging: boolean) => (
  <TaskItem item={item} isDragging={isDragging} />
), []);

2. Provide Visual Feedback

Always indicate when an item is being dragged:

renderItem={(item, isDragging) => (
  <View style={[
    styles.item,
    isDragging && {
      opacity: 0.9,
      transform: [{ scale: 1.05 }],
      elevation: 8,
    }
  ]}>
    {/* ... */}
  </View>
)}

3. Stable Keys

Use stable, unique IDs for keyExtractor:

// βœ… Good
keyExtractor={(item) => String(item.id)}

// ❌ Bad - index changes during drag
keyExtractor={(item, index) => String(index)}

4. Save Order After Drag

Use the ref to get the final order and update your state/backend:

const handleDragEnd = () => {
  const newOrder = listRef.current?.getCurrentData();
  if (newOrder) {
    // Update local state
    setData(newOrder);
    
    // Persist to backend
    api.updateOrder(newOrder);
  }
};

5. Performance Optimization

For large lists, consider:

// Memoize your item component
const TaskItem = React.memo(({ item, isDragging }) => (
  <View style={[styles.item, isDragging && styles.dragging]}>
    <Text>{item.text}</Text>
  </View>
));

// Use in renderItem
renderItem={(item, isDragging) => (
  <TaskItem item={item} isDragging={isDragging} />
)}

⚑ Performance Tips

  1. Avoid Heavy Computations in renderItem: Keep your render function lightweight
  2. Use React.memo: Memoize item components to prevent unnecessary re-renders
  3. Optimize Images: Use optimized images and consider lazy loading for image-heavy lists
  4. Limit Item Complexity: Keep item components simple for better drag performance
  5. Test on Real Devices: Always test on actual devices, not just simulators

πŸ› Troubleshooting

Drag not working

Solution:

  1. Ensure react-native-gesture-handler is properly installed and configured
  2. Check that your item has a touchable area (sufficient height/width)
  3. Verify that no parent component is blocking touch events

Auto-scroll too fast/slow

Solution: Adjust the autoScrollSpeed prop:

<DraggableList autoScrollSpeed={5} /> // Slower
<DraggableList autoScrollSpeed={15} /> // Faster

TypeScript errors with custom item types

Solution: Make sure your item interface extends TItem:

import { TItem } from 'react-native-draggable-order-list';

interface MyItem extends TItem {
  id: number;
  // ... other properties
}

Items not swapping correctly with variable heights

Solution: The library automatically measures item heights. Ensure your items have consistent padding and margins, and avoid using flex: 1 on item containers.

🀝 Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

πŸ“„ License

MIT Β© Fadion1996

πŸ™ Acknowledgments

Built with:


Made with ❀️ for the React Native community