BETA We're building something new — all help is welcome! Contribute →

Drag & Drop

Reorder lists with drag and drop using SortableJS integration.

Basic Usage

Use v-sort on a container and v-sort-item on each draggable item:

Template
<ul v-sort="'reorder'">
    <li v-for="item in items"
        :key="item.id"
        v-sort-item="item.id">
        {{ item.name }}
    </li>
</ul>
Component
public function reorder(
    int|string $item,
    int $position
): void {
    // $item = ID from v-sort-item
    // $position = new index (0-based)

    $index = array_search(
        $item,
        array_column($this->items, 'id')
    );
    $moved = $this->items[$index];
    array_splice($this->items, $index, 1);
    array_splice($this->items, $position, 0, [$moved]);
}

Directives

Directive Description
v-sort="'method'" Sortable container, calls PHP method on drop
v-sort-item="id" Draggable item with unique ID
v-sort-handle Drag handle (limits drag to this element)
v-sort-ignore Exclude element from drag (buttons, inputs)
v-sort-group="'name'" Enable cross-list dragging between same group

Drag Handle

Limit dragging to a specific element:

<li v-sort-item="item.id">
    <span v-sort-handle class="cursor-grab"></span>
    <span>{{ item.name }}</span>
    <button v-sort-ignore @click="livue.call('delete', [item.id])">
        Delete
    </button>
</li>

Cross-List (Kanban)

Drag items between different lists using v-sort-group:

<!-- TODO List -->
<ul v-sort="'reorderTodo'"
    v-sort-group="'tasks'"
    data-livue-sort-id="todo">
    <li v-for="task in todoTasks" v-sort-item="task.id">
        {{ task.name }}
    </li>
</ul>

<!-- DONE List -->
<ul v-sort="'reorderDone'"
    v-sort-group="'tasks'"
    data-livue-sort-id="done">
    <li v-for="task in doneTasks" v-sort-item="task.id">
        {{ task.name }}
    </li>
</ul>
PHP Handler
public function reorderTodo(
    string $itemId,
    int $position,
    ?string $fromList = null
): void {
    if ($fromList === 'done') {
        // Item moved FROM done list TO todo list
        // Remove from done, insert in todo at $position
    } else {
        // Internal reorder within todo list
    }
}

Modifiers

Modifier Description
.300ms Animation duration
.no-animation Disable animation
.horizontal Horizontal sorting (tabs, toolbar)

CSS Classes

Style the drag states:

.livue-sort-ghost {
    /* Placeholder during drag */
    opacity: 0.5;
    background: #e0f2fe;
}

.livue-sort-chosen {
    /* Item selected before drag */
}

.livue-sort-drag {
    /* Item during drag */
    box-shadow: 0 10px 20px rgba(0,0,0,0.2);
}