Guides

Retool ListView Drag and Drop Reorder: What to Know

OTC Team··5 min read

If you've tried to add Retool ListView drag and drop reorder functionality to your internal tool, you've likely hit the same wall as dozens of other developers in the Retool community. The ListView component and the Reorderable List component exist as two separate tools — and the gap between them causes real friction. This guide breaks down the current state, why it matters, and what you can do right now while Retool's team works toward a native fix.

What Is the Retool Reorderable List and Why Is It Falling Behind?

The Reorderable List component allows users to drag and drop items to change their order — a common UX pattern for priority queues, task lists, ranked selections, and more. The problem is that it's been left behind as Retool has invested heavily in the ListView component, which received a major upgrade in the form of a native grid layout option.

The result is a split ecosystem: you get modern features (grid mode, richer layout options) in ListView, but you lose drag-and-drop reordering. You get reordering in Reorderable List, but you lose the power and flexibility of ListView. Neither component does both — and that's the core issue developers are frustrated about.

Why Merging ListView and Reorderable List Makes Sense

The community case for merging these two components is straightforward. Here's what a unified component would unlock:

  • Drag-and-drop reordering in list mode — letting users manually sort rows just like in Reorderable List, but with the full power of ListView internals.
  • Drag-and-drop reordering in grid mode — a pattern used in Kanban-style tools, image galleries, and card-based dashboards.
  • Stable state when adding rows programmatically — a known bug where adding a new item to a ListView via JavaScript causes all other rows to lose their component state (input values, toggle states, etc.).

All three of these are solvable in a merged, redesigned component. Retool has confirmed that a ListView V2 (alongside a GridView V2) is planned, and reorderability is on the roadmap — though no release date has been set as of this writing.

The Programmatic Row Addition Bug Explained

One of the most painful issues tied to this gap is what happens when you try to add a row to a ListView dynamically. If you update the data source driving your ListView — say, by pushing a new object into a variable or re-running a query — the entire list re-renders. This wipes out any unsaved user input across all existing rows.

For example, if a user has filled in three rows of a form inside a ListView and then clicks "Add Row," all three rows reset. The workaround most developers use is to store component state externally in a variable or localStorage and sync on every change — but this is brittle and adds significant complexity to your app logic.

Current Workarounds for Drag-and-Drop Reordering in Retool

Until a native solution ships, here are the most practical approaches teams are using:

  • Use Reorderable List with a custom template: If your layout needs are simple, lean into Reorderable List and style it as close to your design as possible. You lose ListView's flexibility, but you gain working drag-and-drop.
  • Pair ListView with manual up/down buttons: Add an "↑" and "↓" button inside each ListView row. On click, run a JavaScript transformer that reorders the underlying array and writes it back to a variable. Not as elegant as drag-and-drop, but fully functional and easy to implement.
  • Use a Custom Component with a drag-and-drop library: Libraries like SortableJS or dnd-kit can be embedded in a Retool Custom Component. You pass your list data in via model, handle reorder events, and emit the new order back to Retool via modelUpdate. This is the most powerful option but requires front-end development effort.
  • Preserve state on row addition with a variable: Before adding a new row, use a Script to read all current component values and save them to a variable. After the list re-renders, use setIn or setValue calls to restore each component's state. Tedious, but it works.

How to Implement Up/Down Reordering in a Retool ListView

If you want a no-custom-component solution, here's the step-by-step approach using manual sort buttons:

  • Store your list data in a variable (e.g., listData) as an array of objects.
  • Set your ListView data source to {{ listData.value }}.
  • Inside each ListView row, add two Button components: one for "Move Up" and one for "Move Down."
  • On the "Move Up" button's click handler, run a script: get the current i index from listItem.index, swap the element at i with i - 1 in a copy of the array, and call listData.setValue(newArray).
  • Mirror this logic for "Move Down," swapping with i + 1.
  • Disable the "Move Up" button when {{ listItem.index === 0 }} and "Move Down" when the index equals the last item.

This pattern is stable, requires no external libraries, and works reliably across Retool versions.

What to Expect from Retool ListView V2

Retool's team has acknowledged the demand for a unified, more powerful ListView experience. The planned V2 is expected to address drag-and-drop reordering in both list and grid modes, as well as the component state loss issue when rows are added programmatically. Keep an eye on the Retool changelog and the original community thread for timeline updates. Until then, the workarounds above are your best path forward.

Ready to build?

We scope, design, and ship your Retool app — fast.

Ready to ship your first tool?