Advanced

Drag & Drop

Enable row and column reordering in NuGrid.

NuGrid supports drag and drop for reordering rows and columns.

Row Drag & Drop

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>

Row Drag Options

interface NuGridRowDragOptions {
  enabled: boolean
  sortOrderField?: string
  handleColumn?: boolean
}

Options Reference

OptionTypeDefaultDescription
enabledbooleanfalseEnable row dragging
sortOrderFieldstring-Field to store sort order
handleColumnbooleantrueShow drag handle column

Drag Handle

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>

Persisting Order

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>

Drag Restrictions

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>

Column Drag & Drop

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>

Column Drag Events

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>

Visual Feedback

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>

Drag with Grouping

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>

Example: Kanban-Style Ordering

<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>

Next Steps

Events

Handle grid events.

Excel Export

Export data to Excel.