Data & Editing

Add New Rows

Enable adding new rows to NuGrid.

NuGrid provides a built-in add-new-row feature that displays a special row for adding new items to your data.

Enabling Add Row

Enable the add row feature with the add-new-row prop:

<template>
  <!-- Simple enable -->
  <NuGrid :data="data" :columns="columns" :add-new-row="true" />

  <!-- With options -->
  <NuGrid
    :data="data"
    :columns="columns"
    :add-new-row="{
      position: 'bottom',
      addNewText: 'Add New Item',
    }"
  />
</template>

Add Row Options

OptionTypeDefaultDescription
position'top' | 'bottom' | 'none''bottom'Position of add row
addNewTextstring'Add new...'Placeholder text

Position Options

<template>
  <!-- Add row at bottom (default) -->
  <NuGrid :add-new-row="{ position: 'bottom' }" />

  <!-- Add row at top -->
  <NuGrid :add-new-row="{ position: 'top' }" />

  <!-- Hidden but accessible via keyboard/API -->
  <NuGrid :add-new-row="{ position: 'none' }" />
</template>

Handling New Rows

Listen to the row-add-requested event when a new row is submitted:

<script setup lang="ts">
const data = ref([...])

function handleRowAddRequested(newRow) {
  // Generate ID for the new row
  const maxId = Math.max(...data.value.map(d => d.id), 0)
  newRow.id = maxId + 1

  // Add to data
  data.value = [...data.value, { ...newRow }]

  // Optionally persist to server
  await api.createItem(newRow)

  toast.add({
    title: 'Row Added',
    description: `Added "${newRow.name}"`,
    color: 'success',
  })
}
</script>

<template>
  <NuGrid
    :data="data"
    :columns="columns"
    :add-new-row="true"
    @row-add-requested="handleRowAddRequested"
  />
</template>

Column Configuration for Add Row

Configure how columns behave in the add-new-row:

const columns: NuGridColumn<Product>[] = [
  {
    accessorKey: 'id',
    header: 'ID',
    showNew: false,      // Hide in add row (auto-generated)
  },
  {
    accessorKey: 'name',
    header: 'Name',
    requiredNew: true,   // Required field in add row
  },
  {
    accessorKey: 'category',
    header: 'Category',
    defaultValue: 'General',  // Default value in add row
  },
  {
    accessorKey: 'price',
    header: 'Price',
    validateNew: (value) => {
      if (value !== undefined && value < 0) {
        return { valid: false, message: 'Price must be positive' }
      }
      return { valid: true }
    },
  },
  {
    accessorKey: 'quantity',
    header: 'Quantity',
    showNew: false,      // Server-assigned field
  },
]

Column Add Row Options

OptionTypeDescription
showNewbooleanShow/hide column in add row
requiredNewbooleanMake field required in add row
defaultValueanyDefault value for new rows
validateNewfunctionValidation function for add row

Add Row State

Track the add row state:

<script setup lang="ts">
const gridRef = useTemplateRef('grid')

const addRowState = computed(() => {
  return gridRef.value?.addRowState ?? 'idle'
})
</script>

<template>
  <div>
    <span>Add Row State: {{ addRowState }}</span>
    <NuGrid ref="grid" :data="data" :columns="columns" :add-new-row="true" />
  </div>
</template>

State Values

StateDescription
idleAdd row not active
focusedAdd row is focused
editingActively editing add row

Keyboard Navigation

KeyAction
Arrow Down from last rowFocus add row
Arrow Up from add rowReturn to data rows
Enter in add rowSubmit new row
Escape in add rowCancel and clear
TabMove between add row cells

Add Row with Grouping

When grouping is enabled, add rows can appear at the group level:

<script setup lang="ts">
const grouping = ref(['category'])
</script>

<template>
  <NuGrid
    v-model:grouping="grouping"
    :data="data"
    :columns="columns"
    :add-new-row="{ position: 'bottom' }"
  />
</template>

Validation in Add Row

Combine with validation for robust data entry:

<script setup lang="ts">
import { z } from 'zod'

const productSchema = z.object({
  name: z.string().min(2, 'Name must be at least 2 characters'),
  price: z.coerce.number().min(0.01, 'Price must be greater than 0'),
  category: z.string().min(1, 'Category is required'),
})

const validationOptions = {
  schema: productSchema,
  validateOn: 'reward',
  showErrors: 'always',
  onInvalid: 'block',
}
</script>

<template>
  <NuGrid
    :data="data"
    :columns="columns"
    :add-new-row="true"
    :validation="validationOptions"
    @row-add-requested="handleRowAddRequested"
  />
</template>

Styling Add Row

The add row receives a data-add-row="true" attribute for styling:

<template>
  <NuGrid
    :data="data"
    :columns="columns"
    :add-new-row="true"
    :ui="{
      tbody: '[data-add-row=true]:bg-primary/5',
    }"
  />
</template>

Or with custom CSS:

[data-add-row='true'] {
  border-inline: 1px dashed var(--ui-border);
  background: linear-gradient(90deg, var(--ui-primary) / 0.06, transparent 35%);
}

[data-add-row='true'] td:first-child::before {
  content: '+ Add';
  color: var(--ui-primary);
  font-weight: 600;
}

Example: Complete Add Row Implementation

<script setup lang="ts">
import { z } from 'zod'

interface Product {
  id: number
  name: string
  category: string
  price: number
  stock: number
}

const data = ref<Product[]>([
  { id: 1, name: 'Laptop', category: 'Electronics', price: 999, stock: 10 },
  { id: 2, name: 'Mouse', category: 'Electronics', price: 29, stock: 50 },
])

const columns: NuGridColumn<Product>[] = [
  { accessorKey: 'id', header: 'ID', showNew: false },
  { accessorKey: 'name', header: 'Name', requiredNew: true },
  { accessorKey: 'category', header: 'Category', defaultValue: 'General' },
  { accessorKey: 'price', header: 'Price' },
  { accessorKey: 'stock', header: 'Stock', showNew: false },
]

const toast = useToast()

function handleRowAddRequested(newRow: Partial<Product>) {
  const maxId = Math.max(...data.value.map(d => d.id), 0)

  const product: Product = {
    id: maxId + 1,
    name: newRow.name!,
    category: newRow.category || 'General',
    price: newRow.price || 0,
    stock: 0,
  }

  data.value = [...data.value, product]

  toast.add({
    title: 'Product Added',
    description: `Added "${product.name}"`,
    color: 'success',
  })
}
</script>

<template>
  <NuGrid
    :data="data"
    :columns="columns"
    :add-new-row="{ position: 'bottom', addNewText: 'Add New Product' }"
    :editing="{ enabled: true, startClicks: 'single' }"
    @row-add-requested="handleRowAddRequested"
  />
</template>

Next Steps

Validation

Validate cell values with schemas.

Cell Data Types

Use built-in cell types.