Introducing PrimeReact v11-alpha 🎉Discover Now

usePickList

A headless hook that manages two lists with transfer, reorder, and optional drag-and-drop between them.

New York
Rome
London
Istanbul
Paris
basic-demo

Usage#

import { usePickList } from '@primereact/headless/picklist';
const pickList = usePickList({
    source,
    target,
    selection,
    draggable: true,
    onChange: (e) => {
        setSource(e.source);
        setTarget(e.target);
    }
});
 
<div {...pickList.rootProps}>
    <div {...pickList.sourceListProps}>
        {pickList.state.source.map((item, i) => (
            <div key={i} {...pickList.getOptionProps(item, i, 'source')}>
                {item.name}
            </div>
        ))}
    </div>
    <div>
        <button {...pickList.moveToTargetProps}>→</button>
        <button {...pickList.moveAllToTargetProps}>⇉</button>
        <button {...pickList.moveToSourceProps}>←</button>
        <button {...pickList.moveAllToSourceProps}>⇇</button>
    </div>
    <div {...pickList.targetListProps}>
        {pickList.state.target.map((item, i) => (
            <div key={i} {...pickList.getOptionProps(item, i, 'target')}>
                {item.name}
            </div>
        ))}
    </div>
</div>;

usePickList manages two lists with transfer and reorder operations. Pair it with Listbox for built-in selection and keyboard navigation.

Features#

  • Two-list state — keeps source and target arrays in sync and emits a single onChange for any mutation
  • Transfer operationsmoveToTarget, moveToSource, moveAllToTarget, moveAllToSource with pre-wired button props
  • Per-side reorder controls — independent prev/next/first/last props for each list plus matching imperative methods
  • Drag-and-drop — optional pointer reorder within a list and transfer across lists with scope validation
  • Side-aware option propsgetOptionProps(item, index, 'source' | 'target') returns the attributes each row needs

Working with callbacks#

onChange — keep both arrays in state#

Transfer and reorder both funnel through onChange. Apply e.source and e.target back to state in one step.

const [source, setSource] = React.useState(initialSource);
const [target, setTarget] = React.useState([]);
 
const pickList = usePickList({
    source,
    target,
    onChange: (e) => {
        setSource(e.source);
        setTarget(e.target);
    }
});

Tracking selection per side#

Selection is shared across both lists. Mirror it externally so transfer buttons know which items to move.

const [selection, setSelection] = React.useState([]);
 
const pickList = usePickList({
    source,
    target,
    selection,
    onSelectionChange: (e) => setSelection(e.value),
    onChange: (e) => {
        setSource(e.source);
        setTarget(e.target);
    }
});

Cross-list drag with clone placeholder#

Enable draggable to allow reorder within a list and transfer across lists in one gesture. Switch the placeholder to clone when users benefit from seeing the original position.

const pickList = usePickList({
    source,
    target,
    draggable: true,
    placeholder: 'clone',
    onChange: (e) => {
        setSource(e.source);
        setTarget(e.target);
    }
});

Driving transfers from custom UI#

Call the imperative methods directly when you want to trigger moves from keyboard shortcuts or a menu.

const pickList = usePickList({ source, target, selection, onChange });
 
useHotkey('alt+right', () => pickList.moveToTarget());
useHotkey('alt+shift+right', () => pickList.moveAllToTarget());

Styling with data attributes#

Every prop object includes data-scope and data-part attributes for CSS targeting.

[data-scope='picklist'][data-part='root'] {
    display: flex;
    gap: 1rem;
}
 
[data-scope='picklist'][data-part='source-list'],
[data-scope='picklist'][data-part='target-list'] {
    min-height: 200px;
}
 
[data-sortable-placeholder] {
    opacity: 0.4;
}

Option Attributes#

AttributeValue
data-selectedPresent when the item is selected
data-sortable-itemPresent on every sortable item
data-sortable-containerContainer id for the sortable group
data-draggingPresent on the item being dragged
data-droppingPresent briefly during the drop animation
data-sortable-placeholderPresent on the placeholder clone left behind during drag

API#

usePickList#

Accessibility#

Arrow keys navigate within each list, Tab moves between lists, and Enter moves selection across lists. See Primitive for full WAI-ARIA compliance details.