<script setup lang="ts"> import { onMounted, ref } from "vue"; import Sortable from "sortablejs"; const leftList = defineModel<string[]>("leftList", { required: true }); const rightList = defineModel<string[]>("rightList", { required: true }); const leftListElement = ref<HTMLUListElement | undefined>(undefined); const rightListElement = ref<HTMLUListElement | undefined>(undefined); onMounted(() => { if (leftListElement.value && rightListElement.value) { new Sortable(leftListElement.value, { group: "shared", animation: 150, sort: false, // To disable sorting: set sort to false onRemove: (evt) => { leftList.value.splice(evt.oldIndex ?? 0, 1); }, onAdd: (evt) => { leftList.value.splice( evt.newIndex ?? 0, 0, (evt.item as HTMLLIElement).innerText, ); }, }); new Sortable(rightListElement.value, { group: "shared", animation: 150, sort: false, // To disable sorting: set sort to false onRemove: (evt) => { rightList.value.splice(evt.oldIndex ?? 0, 1); }, onAdd: (evt) => { rightList.value.splice( evt.newIndex ?? 0, 0, (evt.item as HTMLLIElement).innerText, ); }, }); } }); </script> <template> <div class="row"> <div class="col-6 d-flex flex-column justify-content-start"> <h5><slot name="leftHeader" /></h5> <ul id="items" class="list-group flex-fill border border-dashed p-1 overflow-y-scroll" ref="leftListElement" style="max-height: 40vh" > <li v-for="(left, index) in leftList" class="list-group-item" :key="left" @click=" rightList.push(left); leftList.splice(index, 1); " > {{ left }} </li> </ul> </div> <div class="col-6 d-flex flex-column justify-content-start"> <h5><slot name="rightHeader" /></h5> <ul id="items" class="list-group flex-fill border border-dashed p-1 overflow-y-scroll" ref="rightListElement" style="max-height: 40vh" > <li v-for="(right, index) in rightList" class="list-group-item" :key="right" @click=" leftList.push(right); rightList.splice(index, 1); " > {{ right }} </li> </ul> </div> </div> </template> <style scoped> li:hover { cursor: grab; background: var(--bs-secondary-bg-subtle); } .border-dashed { border-style: dashed !important; } </style>