Svelte — Swap two items
Use swap in Svelte to exchange only two items and inspect the completion event.
Different from insertion sorting
Section titled “Different from insertion sorting”Dropping A on the center of C in [A, B, C, D] produces [C, B, A, D]. Only the two items exchange positions; B and D remain. Intervening items are not shifted as they would be for insertion.
- Drag the A handle to the center of C and release.
- Check JSON for
status: "dropped",change.operation: "swap",change.itemId: "A", andchange.swapItemId: "C". - Start another drag and cancel with Escape; order remains unchanged.
- Reset returns to A, B, C, D.
Public options
Section titled “Public options”| Option | Value/purpose |
|---|---|
swap |
true — exchanges source and target within the same area. |
direction |
"vertical" — this example uses one vertical list. |
itemKey or data-sortable-id |
Supplies identity retained across movement. |
handle |
".task-handle" — restricts pointer input to handles. |
Svelte state commit
Section titled “Svelte state commit”createSortableScope / use:sortable · items / onItemsChange
Commit the adapter’s next array to state immediately. Do not mutate the original array or use index-based keys. Check both the onAfterDrag completion result and the displayed order.
The component owns the Svelte scope and destroys it in onDestroy. Reactive action options propagate changes to items.
This is a same-area, single-item swap. Grid collision, multiDrag, threshold/invertSwap combinations, and cross-area delivery remain separate scenarios. This pointer-based example does not claim full keyboard reordering simply because its handle is focusable.
Related documentation
Section titled “Related documentation”Advanced sorting guide · Core lifecycle · Vanilla instance · Ordinary list transfer
Try it live
Section titled “Try it live”<script lang="ts"> import { onDestroy } from 'svelte'; import { createSortableScope, sortable } from 'comins-sortable/svelte'; import type { AfterDragResult } from 'comins-sortable/core'; import 'comins-sortable/styles.css'; export let lang = 'ko'; const ko = lang === 'ko'; type Item = { id: string }; const initial: Item[] = ['A','B','C','D'].map(id => ({ id })); let items: Item[] = [...initial]; let result: AfterDragResult | null = null; const scope = createSortableScope<Item>({ onAfterDrag: event => { result = event; } }); onDestroy(() => scope.destroy()); $: options = { scope, areaId: 'items', items, itemKey: 'id' as const, swap: true, direction: 'vertical' as const, handle: '.task-handle', onItemsChange: (next: readonly Item[]) => { items = [...next]; } };</script><div class="demo" data-demo="swap-svelte"> <div class="demo-toolbar"><span>{ko ? 'A의 손잡이를 C의 중앙에 놓으십시오.' : 'Drop the A handle onto the center of C.'}</span><button on:click={() => { scope.cancel(); items = [...initial]; result = null; }}>{ko ? '초기화' : 'Reset'}</button></div> <div class="task-list swap-list" use:sortable={options}> {#each items as item (item.id)}<div class="task" data-swap-id={item.id}><button class="task-handle" aria-label={`Drag ${item.id}`}>⠿</button><span>{item.id}</span></div>{/each} </div> <p role="status" data-swap-order>{items.map(item => item.id).join(', ')}</p> <pre data-swap-result>{JSON.stringify(result, null, 2)}</pre></div>