apps/docs/solid/hooks/use-sortable.mdx
import {Story} from '/snippets/story.mdx'; import {CodeSandbox} from '/snippets/sandbox.mdx'; import {sortableStyles} from '/snippets/code.mdx';
<Story id="sortable-vertical-list--basic-setup" framework="solid" height="320" hero />The useSortable hook combines draggable and droppable behavior with sorting logic. Import it from @dnd-kit/solid/sortable.
<CodeSandbox template="solid" files={{ 'App.tsx': {code: appCode, active: true}, 'styles.css': {code: sortableStyles, hidden: true}, }} height={560} previewHeight={180} />
<Note> Use **getter syntax** for reactive props to maintain Solid's fine-grained reactivity. Without getters, the hook reads prop values once during setup and never re-runs its effects when they change. </Note>The example above uses the move helper from @dnd-kit/helpers, a convenience function that takes your items and a drag event and returns a new array with the item moved to its new position. It supports flat arrays and grouped records, handles canceled drags, and works with optimistic sorting out of the box.
If you need more control over state updates, you can manage state manually using the isSortable type guard and the sortable properties (initialIndex, index).
With optimistic sorting enabled (the default), you only need to handle the onDragEnd event:
import {createSignal, For} from 'solid-js';
import {DragDropProvider} from '@dnd-kit/solid';
import {useSortable, isSortable} from '@dnd-kit/solid/sortable';
function SortableItem(props) {
const {ref} = useSortable({
get id() { return props.id; },
get index() { return props.index; },
});
return <li ref={ref} class="item">Item {props.id}</li>;
}
export default function App() {
const [items, setItems] = createSignal([1, 2, 3, 4]);
return (
<DragDropProvider
onDragEnd={(event) => {
if (event.canceled) return;
const {source} = event.operation;
if (isSortable(source)) {
const {initialIndex, index} = source;
if (initialIndex !== index) {
setItems((items) => {
const newItems = [...items];
const [removed] = newItems.splice(initialIndex, 1);
newItems.splice(index, 0, removed);
return newItems;
});
}
}
}}
>
<ul class="list">
<For each={items()}>
{(id, index) => <SortableItem id={id} index={index()} />}
</For>
</ul>
</DragDropProvider>
);
}
export const appCode = ` import {createSignal, For} from 'solid-js'; import {DragDropProvider} from '@dnd-kit/solid'; import {useSortable} from '@dnd-kit/solid/sortable'; import {move} from '@dnd-kit/helpers'; import './styles.css';
function SortableItem(props) { const {ref} = useSortable({ get id() { return props.id; }, get index() { return props.index; }, });
return <li ref={ref} class="item">Item {props.id}</li>; }
export default function App() { const [items, setItems] = createSignal([1, 2, 3, 4]);
return ( <DragDropProvider onDragEnd={(event) => { setItems((items) => move(items, event)); }} > <ul class="list"> <For each={items()}> {(id, index) => <SortableItem id={id} index={index()} />} </For> </ul> </DragDropProvider> ); } `.trim();