Advanced

Events

Grid events and event handling.

NuGrid emits various events that allow you to respond to user interactions and state changes.

Interactive Demo

Available Events

EventPayloadDescription
cell-value-changed{ row, column, oldValue, newValue }Cell value was edited
row-selection-changedRecord<string, boolean>Row selection changed
focused-cell-changed{ rowId, columnId }Focused cell changed
row-dragged{ originalIndex, newIndex }Row was dragged to new position
row-add-requestedrowDataNew row was finalized
state-changedNuGridStateSnapshotGrid state changed
ready-Grid finished initializing

Cell Value Changed

Fires when a cell edit is committed:

<script setup lang="ts">
function onCellValueChanged(event) {
  console.log('Cell changed:', {
    row: event.row.original,
    column: event.column.id,
    oldValue: event.oldValue,
    newValue: event.newValue,
  })
}
</script>

<template>
  <NuGrid
    :data="data"
    :columns="columns"
    :editing="{ enabled: true }"
    @cell-value-changed="onCellValueChanged"
  />
</template>

Row Selection Changed

Fires when row selection changes:

<script setup lang="ts">
function onSelectionChanged(selection: Record<string, boolean>) {
  const selectedIds = Object.entries(selection)
    .filter(([, selected]) => selected)
    .map(([id]) => id)

  console.log('Selected IDs:', selectedIds)
}
</script>

<template>
  <NuGrid
    :data="data"
    :columns="columns"
    :selection="{ mode: 'multi' }"
    @row-selection-changed="onSelectionChanged"
  />
</template>

Focused Cell Changed

Fires when focus moves to a different cell:

<script setup lang="ts">
function onFocusedCellChanged(event: { rowId: string | null, columnId: string | null }) {
  console.log('Focus moved to:', event)
}
</script>

<template>
  <NuGrid
    :data="data"
    :columns="columns"
    :focus="{ mode: 'cell' }"
    @focused-cell-changed="onFocusedCellChanged"
  />
</template>

Row Dragged

Fires when a row is dragged to a new position:

<script setup lang="ts">
function onRowDragged(event: { originalIndex: number, newIndex: number }) {
  console.log(`Row moved from ${event.originalIndex} to ${event.newIndex}`)
}
</script>

<template>
  <NuGrid
    :data="data"
    :columns="columns"
    :row-drag-options="{ enabled: true }"
    @row-dragged="onRowDragged"
  />
</template>

Complete Example

<script setup lang="ts">
import type { NuGridColumn } from '#nu-grid/types'

const toast = useToast()
const eventLog = ref<string[]>([])

function logEvent(message: string) {
  eventLog.value.unshift(`${new Date().toLocaleTimeString()}: ${message}`)
  if (eventLog.value.length > 10) eventLog.value.pop()
}

function onCellValueChanged(event) {
  logEvent(`Cell "${event.column.id}" changed: ${event.oldValue}${event.newValue}`)
}

function onSelectionChanged(selection: Record<string, boolean>) {
  const count = Object.values(selection).filter(Boolean).length
  logEvent(`Selection changed: ${count} row(s) selected`)
}

function onFocusedCellChanged(event) {
  logEvent(`Focus: row ${event.rowId}, column ${event.columnId}`)
}

const data = ref([
  { id: 1, name: 'Alice', status: 'active' },
  { id: 2, name: 'Bob', status: 'inactive' },
])

const columns: NuGridColumn<User>[] = [
  { accessorKey: 'id', header: 'ID' },
  { accessorKey: 'name', header: 'Name' },
  { accessorKey: 'status', header: 'Status' },
]
</script>

<template>
  <div class="grid md:grid-cols-2 gap-4">
    <NuGrid
      :data="data"
      :columns="columns"
      :editing="{ enabled: true, startClicks: 'double' }"
      :selection="{ mode: 'multi' }"
      :focus="{ mode: 'cell' }"
      @cell-value-changed="onCellValueChanged"
      @row-selection-changed="onSelectionChanged"
      @focused-cell-changed="onFocusedCellChanged"
    />

    <div class="border rounded p-4">
      <h3 class="font-semibold mb-2">Event Log</h3>
      <ul class="text-sm space-y-1">
        <li v-for="(event, i) in eventLog" :key="i" class="text-muted">
          {{ event }}
        </li>
      </ul>
    </div>
  </div>
</template>
Events are emitted after the action completes, so the grid state is already updated when your handler runs.