Skip to main content

Introducing Workflow Engine, try for FREE workflowengine.io.

Sortable list

Introduction​

SortableList is a Repeater that lets form users reorder rows. It uses the same row template, value array, and addRow / removeRow actions as Repeater.

In the designer you edit one row template. In the viewer each row shows a handle on the left.

The package is @react-form-builder/components-sortable-list and is distributed under the MIT license.

Installation​

npm install @react-form-builder/components-sortable-list

Connection to FormBuilder component​

import {rSuiteComponents, rSuiteComponentsDescriptions} from '@react-form-builder/components-rsuite'
import {sortableListComponent, sortableListComponentsDescriptions} from '@react-form-builder/components-sortable-list'
import {BuilderView, FormBuilder} from '@react-form-builder/designer'

const components = [
...rSuiteComponents.map((c) => c.build()),
sortableListComponent.build(),
]
const builderView = new BuilderView(components)
.withComponentLibraryDescription(rSuiteComponentsDescriptions)
.withComponentLibraryDescription(sortableListComponentsDescriptions)

function App() {
return <FormBuilder view={builderView}/>
}

Connect to FormViewer component​

import {sortableListModel} from '@react-form-builder/components-sortable-list'
import {models} from '@react-form-builder/components-rsuite'
import {createView, FormViewer} from '@react-form-builder/core'

const view = createView([...models, sortableListModel])

Main properties​

In addition to Repeater's Value and Item Render When, SortableList exposes:

NameTypeDescription
DisabledbooleanWhen true, row reordering is disabled.
Read OnlybooleanWhen true, row reordering is disabled.
Reorder Handle Aria LabelstringAccessible name for the drag handle (localizable; default Reorder row).
Item Render WhenstringControls row content rendering like Repeater. Every row still gets a sortable shell; a hidden row can show an empty handle.
ValuearraySame as Repeater: array of row objects.

Disabled and Read Only turn off reordering on Sortable list. Plain Repeater does not offer those as reorder controls.

How reorder works​

When the user finishes a pointer or keyboard reorder, SortableList updates the field with the new array order, the same path as addRow, removeRow, and e.data[key] = [...] on a Repeater. That updates the field's length and order storage and the live form.data view. It does not write back into the viewer props initialData store.

You can also reorder in an action (with or without SortableList) by assigning a new array:

/**
* @param {ActionEventArgs} e - the action arguments.
* @param {{name: string, from: number, to: number}} args - the action parameters arguments.
*/
async function Action(e, args) {
const list = [...(e.data[args.name] ?? [])]
const [row] = list.splice(args.from, 1)
list.splice(args.to, 0, row)
e.data[args.name] = list
}

After either approach, read order from form.data (or e.data). If you keep controlled app state in initialData, apply the full form snapshot from onFormDataChange (including the reordered array). A later stale initialData push can reset order. See Working with form data and Using Repeater.

Keyboard reorder​

You can reorder with the keyboard in the viewer when the list is not disabled or readOnly. Focus the row's reorder handle first; keys pressed elsewhere in the row do not start a move.

Keys​

KeyAction
Space or EnterStart moving the focused row.
ArrowUp / ArrowDownMove the row up or down while a keyboard move is active.
Shift + arrowSame move with a larger step.
Space, Enter, or TabCommit the new order (same as finishing a pointer drag).
EscapeCancel; the value array stays unchanged.

Only up and down change the order. Left and right arrows do not.

Sort sequence (keyboard)​

  1. Focus the handle, then press Space or Enter.
  2. Press ArrowUp or ArrowDown until the row sits where you want it (Shift + arrow moves farther each press).
  3. Press Space, Enter, or Tab to apply the new order through the same setValue path as a pointer drop.
  4. Press Escape instead to cancel.

Order in value / form.data changes only after a completed reorder.

Item Render When and empty shells​

Item Render When hides row content but keeps the row in the list. The handle shell still appears, so a hidden row can show an empty handle. If you need those rows out of the UI, filter them in a custom component and map moves by each row's index in the field value, not only by visible position.

Summary​

  • Use SortableList when users must reorder repeating rows; use Repeater when order is fixed or changed only with addRow / removeRow.
  • Pointer and keyboard reorder both update the field value the same way. Sync controlled initialData from onFormDataChange.
  • Requires React 18 or 19.
  • See Using Repeater for row data, actions, and nested data.
  • Form authors: Sortable list in the Form Author Guide.