Columns
Columns are the foundation of NuGrid. They define how your data is displayed, edited, and interacted with.
<script setup lang="ts">
import type { NuGridColumn } from '#nu-grid/types'
interface Product {
id: number
name: string
price: number
category: string
inStock: boolean
}
const data = ref<Product[]>([
{ id: 1, name: 'Laptop Pro', price: 1299.99, category: 'Electronics', inStock: true },
{ id: 2, name: 'Wireless Mouse', price: 29.99, category: 'Accessories', inStock: true },
{ id: 3, name: 'USB-C Cable', price: 12.99, category: 'Accessories', inStock: false },
{ id: 4, name: 'Monitor 4K', price: 599.99, category: 'Electronics', inStock: true },
{ id: 5, name: 'Keyboard', price: 149.99, category: 'Accessories', inStock: true },
])
const columns: NuGridColumn<Product>[] = [
{
accessorKey: 'id',
header: 'ID',
size: 60,
enableEditing: false,
},
{
accessorKey: 'name',
header: 'Product Name',
size: 150,
},
{
accessorKey: 'price',
header: 'Price',
size: 100,
cell: ({ row }) => `$${row.original.price.toFixed(2)}`,
},
{
accessorKey: 'category',
header: 'Category',
size: 120,
},
{
accessorKey: 'inStock',
header: 'In Stock',
size: 100,
cell: ({ row }) =>
h(
'span',
{
class: row.original.inStock ? 'text-success' : 'text-error',
},
row.original.inStock ? 'Yes' : 'No',
),
},
]
</script>
<template>
<div class="w-full">
<NuGrid
:data="data"
:columns="columns"
resize-columns
:ui="{
base: 'w-full border-separate border-spacing-0',
thead: '[&>tr]:bg-elevated/50',
th: 'py-2 border-y border-default first:border-l last:border-r first:rounded-l-lg last:rounded-r-lg',
td: 'border-b border-default',
}"
/>
</div>
</template>
Basic Column Definition
At minimum, a column needs an accessorKey that matches a property in your data:
import type { NuGridColumn } from '#nu-grid/types'
interface User {
id: number
name: string
email: string
}
const columns: NuGridColumn<User>[] = [
{ accessorKey: 'id', header: 'ID' },
{ accessorKey: 'name', header: 'Name' },
{ accessorKey: 'email', header: 'Email' },
]
Column Properties
Sizing
Control column width with sizing properties:
const columns: NuGridColumn<User>[] = [
{
accessorKey: 'id',
header: 'ID',
size: 60, // Default width in pixels
minSize: 40, // Minimum width when resizing
maxSize: 100, // Maximum width when resizing
},
{
accessorKey: 'name',
header: 'Name',
size: 200,
minSize: 100,
},
]
Feature Toggles
Enable or disable features per column:
const columns: NuGridColumn<User>[] = [
{
accessorKey: 'id',
header: 'ID',
enableSorting: false, // Disable sorting for this column
enableEditing: false, // Disable editing for this column
enableResizing: false, // Disable resizing for this column
enableHiding: false, // Prevent column from being hidden
enablePinning: true, // Allow column pinning
},
]
Custom Cell Rendering
Customize how cell content is displayed:
const columns: NuGridColumn<User>[] = [
{
accessorKey: 'name',
header: 'Name',
cell: ({ row }) => {
return h('div', { class: 'flex items-center gap-2' }, [
h('img', { src: row.original.avatar, class: 'w-6 h-6 rounded-full' }),
h('span', row.original.name),
])
},
},
{
accessorKey: 'status',
header: 'Status',
cell: ({ row }) => {
const colors = {
active: 'text-success',
inactive: 'text-error',
}
return h('span', { class: colors[row.original.status] }, row.original.status)
},
},
]
Cell Template Slots
As an alternative to render functions, you can use template slots for cell customization. This makes it easy to use Vue directives and integrate with Nuxt UI components:
<NuGrid :columns="columns" :data="data">
<template #name-cell="{ value, row }">
<div class="flex items-center gap-2">
<UAvatar :src="row.original.avatar" size="xs" />
<span>{{ value }}</span>
</div>
</template>
<template #status-cell="{ value }">
<UBadge :color="value === 'active' ? 'success' : 'error'">
{{ value }}
</UBadge>
</template>
</NuGrid>
Cell slots work seamlessly with editing - when a cell enters edit mode, the editor is shown instead of the slot content.
Cell Slot Props
| Prop | Type | Description |
|---|---|---|
cell | Cell<T> | NuGrid cell object |
row | Row<T> | NuGrid row object |
column | Column<T> | NuGrid column definition |
value | unknown | Cell value (shortcut for cell.getValue()) |
cellIndex | number | Index of cell in the row |
isEditing | boolean | Whether cell is currently in edit mode |
isInvalid | boolean | Whether cell has validation error |
Custom Header Rendering
Customize the column header:
const columns: NuGridColumn<User>[] = [
{
accessorKey: 'email',
header: ({ column }) => {
const isSorted = column.getIsSorted()
return h(UButton, {
color: 'neutral',
variant: 'ghost',
label: 'Email',
icon: isSorted === 'asc' ? 'i-lucide-arrow-up' : 'i-lucide-arrow-down',
onClick: () => column.toggleSorting(),
})
},
},
]
Cell Data Types
NuGrid includes built-in cell types for common data formats. These provide appropriate formatting and editing:
const columns: NuGridColumn<Product>[] = [
{ accessorKey: 'name', header: 'Name', cellDataType: 'text' },
{ accessorKey: 'price', header: 'Price', cellDataType: 'currency' },
{ accessorKey: 'quantity', header: 'Qty', cellDataType: 'number' },
{ accessorKey: 'active', header: 'Active', cellDataType: 'boolean' },
{ accessorKey: 'createdAt', header: 'Created', cellDataType: 'date' },
{ accessorKey: 'rating', header: 'Rating', cellDataType: 'rating' },
]
Available Cell Types
| Type | Description |
|---|---|
text | Plain text with text input editor |
number | Numeric values with number input |
currency | Currency formatted values |
boolean | Checkbox display and editor |
date | Date values with date picker |
rating | Star rating display |
selection | Dropdown selection |
lookup | Lookup from options |
action-menu | Action menu column |
Column Groups
Group related columns under a common header:
import { createColumnHelper } from '#nu-grid'
const columnHelper = createColumnHelper<User>()
const columns = [
columnHelper.group({
id: 'personal',
header: 'Personal Info',
columns: [
{ accessorKey: 'name', header: 'Name' },
{ accessorKey: 'email', header: 'Email' },
],
}),
columnHelper.group({
id: 'work',
header: 'Work Info',
columns: [
{ accessorKey: 'department', header: 'Department' },
{ accessorKey: 'role', header: 'Role' },
],
}),
]
Column Pinning
Pin columns to the left or right edge:
<script setup lang="ts">
const columnPinning = ref({
left: ['id', '__selection'], // Pin selection and ID to left
right: ['__actions'], // Pin actions to right
})
</script>
<template>
<NuGrid
v-model:column-pinning="columnPinning"
:data="data"
:columns="columns"
/>
</template>
Column Visibility
Control which columns are visible:
<script setup lang="ts">
const columnVisibility = ref({
email: false, // Hide email column
phone: false, // Hide phone column
})
</script>
<template>
<NuGrid
v-model:column-visibility="columnVisibility"
:data="data"
:columns="columns"
/>
</template>
Column Resizing
Enable column resizing:
<template>
<NuGrid
:data="data"
:columns="columns"
resize-columns
:column-sizing-options="{
columnResizeMode: 'onChange',
}"
/>
</template>
Column Defaults
Set default options for all columns using the columnDefaults prop:
<template>
<NuGrid
:data="data"
:columns="columns"
:column-defaults="{
resize: true,
reorder: true,
wrapText: false,
sortIcons: {
unsorted: 'i-lucide-chevrons-up-down',
asc: 'i-lucide-arrow-up-narrow-wide',
desc: 'i-lucide-arrow-down-wide-narrow',
},
menu: {
visibilityToggle: true,
button: { icon: 'i-lucide-settings' },
},
}"
/>
</template>
Column Defaults Options
| Option | Type | Default | Description |
|---|---|---|---|
resize | boolean | false | Enable column resizing by default |
reorder | boolean | false | Enable column reordering by default |
wrapText | boolean | false | Enable text wrapping by default |
sortIcons | object | See below | Default sort icon configuration |
menu | object | See below | Default column menu configuration |
lookup | object | See below | Default lookup configuration |
Sort Icons Configuration
{
unsorted: 'i-lucide-chevrons-up-down',
asc: 'i-lucide-arrow-up',
desc: 'i-lucide-arrow-down',
unsortedHover: true, // Show unsorted icon on hover
position: 'edge', // 'edge' | 'inline'
}
Column Menu Configuration
{
preset: 'minimal', // 'minimal' | 'full'
visibilityToggle: true, // Show column visibility toggle
button: {
icon: 'i-lucide-more-vertical',
color: 'neutral',
variant: 'ghost',
},
}
Lookup Configuration
Default settings for all cellDataType: 'lookup' columns:
{
valueKey: 'value',
labelKey: 'label',
searchable: true,
placeholder: 'Select...',
clearable: false,
autoOpen: true,
}
Overriding Defaults Per Column
Column-level settings override the defaults:
const columns: NuGridColumn<User>[] = [
{
accessorKey: 'id',
header: 'ID',
enableResizing: false, // Override default resize: true
},
{
accessorKey: 'name',
header: 'Name',
// Uses default resize: true from columnDefaults
},
]
Summary & Aggregates
Define aggregate calculations for columns to display in group summaries and grand totals:
const columns: NuGridColumn<Product>[] = [
{
accessorKey: 'quantity',
header: 'Qty',
summary: {
aggregate: 'sum',
format: (v) => v.toLocaleString(),
},
},
{
accessorKey: 'price',
header: 'Price',
summary: {
aggregate: 'avg',
format: (v) => `$${v.toFixed(2)}`,
},
},
{
accessorKey: 'rating',
header: 'Rating',
summary: {
aggregate: 'avg',
format: (v) => `${v.toFixed(1)} ★`,
},
},
]
Summary Configuration Options
| Option | Type | Description |
|---|---|---|
aggregate | 'sum' | 'avg' | 'count' | 'min' | 'max' | Function | Built-in aggregate type or custom function |
format | (value, context) => string | Format the calculated value for display |
label | string | Optional label override |
Built-in Aggregates
| Aggregate | Description |
|---|---|
sum | Sum of all values |
avg | Average of all values |
count | Count of rows |
min | Minimum value |
max | Maximum value |
Custom Aggregate Function
{
accessorKey: 'status',
header: 'Status',
summary: {
aggregate: (rows) => {
const active = rows.filter(r => r.status === 'active').length
return `${active}/${rows.length}`
},
},
}
See Grouping for enabling summaries at the grid level.
Add Row Column Options
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 in add row
},
{
accessorKey: 'price',
header: 'Price',
defaultValue: 0, // Default value in add row
validateNew: (value) => {
if (value < 0) {
return { valid: false, message: 'Price must be positive' }
}
return { valid: true }
},
},
]