NuGrid supports drag and drop for reordering rows and columns.
Enable row reordering:
<script setup lang="ts">
const rowDragOptions = {
enabled: true,
}
function onRowDragged(event) {
console.log('Row moved:', {
from: event.originalIndex,
to: event.newIndex,
})
}
</script>
<template>
<NuGrid
:data="data"
:columns="columns"
:row-drag-options="rowDragOptions"
@row-dragged="onRowDragged"
/>
</template>
interface NuGridRowDragOptions {
enabled: boolean
sortOrderField?: string
handleColumn?: boolean
}
| Option | Type | Default | Description |
|---|---|---|---|
enabled | boolean | false | Enable row dragging |
sortOrderField | string | - | Field to store sort order |
handleColumn | boolean | true | Show drag handle column |
By default, a drag handle column is added. Disable it to make entire rows draggable:
<template>
<NuGrid
:data="data"
:columns="columns"
:row-drag-options="{
enabled: true,
handleColumn: false, // No handle, drag entire row
}"
/>
</template>
Use sortOrderField to track order:
<script setup lang="ts">
interface Task {
id: number
name: string
sortOrder: number
}
const data = ref<Task[]>([
{ id: 1, name: 'Task 1', sortOrder: 0 },
{ id: 2, name: 'Task 2', sortOrder: 1 },
{ id: 3, name: 'Task 3', sortOrder: 2 },
])
function onRowDragged(event) {
// Data is automatically reordered
// Save to server
saveTaskOrder(data.value.map((t, i) => ({
id: t.id,
sortOrder: i,
})))
}
</script>
<template>
<NuGrid
:data="data"
:columns="columns"
:row-drag-options="{
enabled: true,
sortOrderField: 'sortOrder',
}"
@row-dragged="onRowDragged"
/>
</template>
Disable dragging for specific rows:
<script setup lang="ts">
const rowDragOptions = {
enabled: true,
canDrag: (row) => {
// Can't drag completed tasks
return row.original.status !== 'completed'
},
canDrop: (draggedRow, targetRow) => {
// Can't drop into different categories
return draggedRow.original.category === targetRow.original.category
},
}
</script>
Enable column reordering:
<script setup lang="ts">
const columnOrder = ref(['id', 'name', 'email', 'status'])
</script>
<template>
<NuGrid
v-model:column-order="columnOrder"
:data="data"
:columns="columns"
column-drag
/>
</template>
Listen to column reorder events:
<script setup lang="ts">
function onColumnOrderChanged(newOrder) {
console.log('New column order:', newOrder)
// Persist order
localStorage.setItem('columnOrder', JSON.stringify(newOrder))
}
</script>
<template>
<NuGrid
v-model:column-order="columnOrder"
:data="data"
:columns="columns"
column-drag
@column-order-changed="onColumnOrderChanged"
/>
</template>
Customize drag styling:
<template>
<NuGrid
:data="data"
:columns="columns"
:row-drag-options="{ enabled: true }"
:ui="{
tbody: `
[&>tr[data-dragging=true]]:opacity-50
[&>tr[data-drag-over=true]]:bg-primary/10
[&>tr[data-drag-over=true]]:border-t-2
[&>tr[data-drag-over=true]]:border-primary
`,
}"
/>
</template>
Row drag works with grouping:
<script setup lang="ts">
const grouping = ref(['category'])
// Rows can be dragged within groups
const rowDragOptions = {
enabled: true,
respectGrouping: true, // Can only drag within same group
}
</script>
<template>
<NuGrid
v-model:grouping="grouping"
:data="data"
:columns="columns"
:row-drag-options="rowDragOptions"
/>
</template>
<script setup lang="ts">
import type { NuGridRowDragEvent } from '#nu-grid/types'
interface Task {
id: number
title: string
priority: number
status: 'todo' | 'doing' | 'done'
}
const data = ref<Task[]>([
{ id: 1, title: 'Design mockups', priority: 1, status: 'todo' },
{ id: 2, title: 'Setup project', priority: 2, status: 'todo' },
{ id: 3, title: 'Build components', priority: 3, status: 'doing' },
{ id: 4, title: 'Write tests', priority: 4, status: 'todo' },
])
const toast = useToast()
const rowDragOptions = {
enabled: true,
sortOrderField: 'priority',
}
async function onRowDragged(event: NuGridRowDragEvent<Task>) {
const { row, originalIndex, newIndex } = event
toast.add({
title: 'Task Reordered',
description: `Moved "${row.original.title}" from #${originalIndex + 1} to #${newIndex + 1}`,
color: 'success',
})
// Save new order to API
try {
await api.updateTaskOrder(
data.value.map((task, index) => ({
id: task.id,
priority: index + 1,
}))
)
} catch (error) {
toast.add({
title: 'Failed to save order',
color: 'error',
})
}
}
const columns: NuGridColumn<Task>[] = [
{ accessorKey: 'priority', header: '#', size: 50 },
{ accessorKey: 'title', header: 'Task' },
{
accessorKey: 'status',
header: 'Status',
cell: ({ row }) => {
const colors = {
todo: 'warning',
doing: 'info',
done: 'success',
}
return h(UBadge, {
color: colors[row.original.status],
label: row.original.status,
})
},
},
]
</script>
<template>
<NuGrid
:data="data"
:columns="columns"
:row-drag-options="rowDragOptions"
@row-dragged="onRowDragged"
/>
</template>