NuGrid provides built-in cell data types that handle formatting, display, and editing for common data formats.
Different cell data types provide appropriate editors: text input, number input, date picker, and checkbox.
<script setup lang="ts">
import type { NuGridColumn } from '#nu-grid/types'
interface Product {
id: number
name: string
price: number
releaseDate: string
inStock: boolean
}
const data = ref<Product[]>([
{ id: 1, name: 'Laptop', price: 1299.99, releaseDate: '2024-01-15', inStock: true },
{ id: 2, name: 'Mouse', price: 29.99, releaseDate: '2023-06-10', inStock: true },
{ id: 3, name: 'Cable', price: 12.99, releaseDate: '2023-03-22', inStock: false },
{ id: 4, name: 'Monitor', price: 599.99, releaseDate: '2024-08-05', inStock: true },
])
const columns: NuGridColumn<Product>[] = [
{ accessorKey: 'id', header: 'ID', size: 60, enableEditing: false, cellDataType: 'number' },
{ accessorKey: 'name', header: 'Name', size: 120, cellDataType: 'text' },
{
accessorKey: 'price',
header: 'Price',
size: 100,
cellDataType: 'number',
cell: ({ row }) => `$${row.original.price.toFixed(2)}`,
},
{
accessorKey: 'releaseDate',
header: 'Release Date',
size: 130,
cellDataType: 'date',
cell: ({ row }) => new Date(row.original.releaseDate).toLocaleDateString(),
},
{ accessorKey: 'inStock', header: 'In Stock', size: 100, cellDataType: 'boolean' },
]
const toast = useToast()
function onCellValueChanged(event: { row: any; column: any; oldValue: any; newValue: any }) {
toast.add({
title: 'Cell Updated',
description: `${event.column.id}: "${event.oldValue}" → "${event.newValue}"`,
color: 'success',
})
}
</script>
<template>
<div class="w-full">
<p class="mb-3 text-sm text-muted">
Different cell data types provide appropriate editors: text input, number input, date picker,
and checkbox.
</p>
<NuGrid
:data="data"
:columns="columns"
:editing="{ enabled: true, startClicks: 'double' }"
: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',
}"
@cell-value-changed="onCellValueChanged"
/>
</div>
</template>
NuGrid automatically infers data types from your row data, similar to AG Grid. This means you often don't need to manually specify cellDataType for each column.
When data is loaded, NuGrid examines the values in each column and detects the appropriate type:
| Detected Type | Detection Logic |
|---|---|
boolean | Values are true or false |
date | Values are JavaScript Date objects |
currency | String with currency symbol ($123.45) OR number with 2 decimals + column name contains price/cost/amount/total/fee/salary/etc. |
percentage | String with percent sign (45%) OR number 0-1 + column name contains percent/rate/ratio |
number | Numeric values |
text | Default fallback for strings |
// No cellDataType needed - types are inferred automatically!
const columns = [
{ accessorKey: 'name', header: 'Name' }, // Inferred: 'text'
{ accessorKey: 'price', header: 'Price' }, // Inferred: 'currency' (2 decimals + "price")
{ accessorKey: 'discountRate', header: 'Rate' }, // Inferred: 'percentage' (0-1 + "rate")
{ accessorKey: 'inStock', header: 'In Stock' }, // Inferred: 'boolean'
{ accessorKey: 'orderDate', header: 'Date' }, // Inferred: 'date' (Date object)
]
const data = [
{
name: 'Laptop',
price: 1299.99, // Currency: 2 decimals + column name
discountRate: 0.15, // Percentage: 0-1 + column name
inStock: true, // Boolean
orderDate: new Date(), // Date object
},
]
Globally: Set dataTypeInference to false on the grid:
<NuGrid
:data="data"
:columns="columns"
:data-type-inference="false"
/>
Per column: Set cellDataType to false to disable inference for that column:
{
accessorKey: 'price',
header: 'Price',
cellDataType: false, // No inference, use default text rendering
}
Explicit type: Setting any cellDataType value prevents inference for that column:
{
accessorKey: 'amount',
header: 'Amount',
cellDataType: 'number', // Use number, not currency
}
| Type | Description | Display | Editor |
|---|---|---|---|
text | Plain text | Text | Text input |
number | Numeric values | Formatted number | Number input |
currency | Money values | Currency format | Number input |
percentage | Percentage values | Formatted with % | Number input with % |
boolean | True/false values | Checkbox | Checkbox |
date | Date values | Formatted date | Date picker |
rating | Star ratings | Stars | Star selector |
selection | Select from options | Selected value | Dropdown |
lookup | Lookup values | Resolved value | Lookup picker |
action-menu | Row actions | Action button | Menu |
Specify the cellDataType on a column:
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' },
]
Plain text display and editing:
{
accessorKey: 'name',
header: 'Name',
cellDataType: 'text',
}
Numeric values with formatting:
{
accessorKey: 'quantity',
header: 'Quantity',
cellDataType: 'number',
cellDataTypeOptions: {
locale: 'en-US',
minimumFractionDigits: 0,
maximumFractionDigits: 2,
},
}
Money values with currency formatting:
{
accessorKey: 'price',
header: 'Price',
cellDataType: 'currency',
cellDataTypeOptions: {
currency: 'USD',
locale: 'en-US',
},
}
| Option | Type | Default | Description |
|---|---|---|---|
currency | string | 'USD' | Currency code |
locale | string | 'en-US' | Locale for formatting |
Percentage values with % formatting:
{
accessorKey: 'discountRate',
header: 'Discount',
cellDataType: 'percentage',
}
Percentages can be stored as decimals (0-1) or as whole numbers (0-100):
// Stored as decimal (0.15 displays as "15.0%")
{
accessorKey: 'rate',
cellDataType: 'percentage',
percentageStorage: 'decimal', // Default
}
// Stored as whole number (15 displays as "15.0%")
{
accessorKey: 'rate',
cellDataType: 'percentage',
percentageStorage: 'percent',
}
| Option | Type | Default | Description |
|---|---|---|---|
percentageStorage | 'decimal' | 'percent' | 'decimal' | How values are stored |
percentageDecimals | number | 1 | Decimal places to display |
Checkbox display and editing:
{
accessorKey: 'active',
header: 'Active',
cellDataType: 'boolean',
}
Boolean cells render as checkboxes and toggle on click or space key.
Date display with formatting:
{
accessorKey: 'createdAt',
header: 'Created',
cellDataType: 'date',
cellDataTypeOptions: {
format: 'MMM dd, yyyy',
locale: 'en-US',
},
}
| Option | Type | Default | Description |
|---|---|---|---|
format | string | 'PP' | Date format string |
locale | string | System locale | Locale for formatting |
Star rating display:
{
accessorKey: 'rating',
header: 'Rating',
cellDataType: 'rating',
cellDataTypeOptions: {
max: 5,
color: 'yellow',
},
}
| Option | Type | Default | Description |
|---|---|---|---|
max | number | 5 | Maximum rating value |
color | string | 'yellow' | Star color |
Dropdown selection from predefined options:
{
accessorKey: 'status',
header: 'Status',
cellDataType: 'selection',
cellDataTypeOptions: {
options: [
{ label: 'Active', value: 'active' },
{ label: 'Pending', value: 'pending' },
{ label: 'Inactive', value: 'inactive' },
],
},
}
Or with simple string array:
{
accessorKey: 'category',
header: 'Category',
cellDataType: 'selection',
cellDataTypeOptions: {
options: ['Electronics', 'Clothing', 'Food', 'Other'],
},
}
| Option | Type | Description |
|---|---|---|
options | string[] | { label, value }[] | Available options |
placeholder | string | Placeholder text |
searchable | boolean | Enable search |
Lookup values from a reference dataset:
const users = ref([
{ id: 1, name: 'Alice' },
{ id: 2, name: 'Bob' },
{ id: 3, name: 'Carol' },
])
const columns = [
{
accessorKey: 'assigneeId',
header: 'Assignee',
cellDataType: 'lookup',
cellDataTypeOptions: {
options: users,
labelKey: 'name',
valueKey: 'id',
},
},
]
| Option | Type | Description |
|---|---|---|
options | Ref<any[]> | any[] | Lookup data source |
labelKey | string | Key for display label |
valueKey | string | Key for value |
searchable | boolean | Enable search |
Add row actions menu:
{
id: 'actions',
header: 'Actions',
cellDataType: 'action-menu',
}
See Row Actions for complete action menu documentation.
Override the default renderer while keeping the data type:
{
accessorKey: 'status',
header: 'Status',
cellDataType: 'selection',
cellDataTypeOptions: {
options: ['active', 'pending', 'inactive'],
},
// Custom display while keeping selection editor
cell: ({ row }) => {
const colors = {
active: 'success',
pending: 'warning',
inactive: 'error',
}
return h(UBadge, {
color: colors[row.original.status],
label: row.original.status,
})
},
}
Create custom cell types using the cell type registry:
// plugins/custom-cell-types.ts
import { useNuGridCellTypeRegistry } from '#nu-grid'
export default defineNuxtPlugin(() => {
const registry = useNuGridCellTypeRegistry()
registry.register('percentage', {
display: ({ value }) => `${(value * 100).toFixed(1)}%`,
editor: defineComponent({
// Custom editor component
}),
})
})
Then use it:
{
accessorKey: 'completion',
header: 'Progress',
cellDataType: 'percentage',
}
<script setup lang="ts">
interface Product {
id: number
name: string
category: string
price: number
stock: number
active: boolean
rating: number
createdAt: Date
}
const columns: NuGridColumn<Product>[] = [
{
accessorKey: 'name',
header: 'Name',
cellDataType: 'text',
},
{
accessorKey: 'category',
header: 'Category',
cellDataType: 'selection',
cellDataTypeOptions: {
options: ['Electronics', 'Clothing', 'Food', 'Home'],
},
},
{
accessorKey: 'price',
header: 'Price',
cellDataType: 'currency',
cellDataTypeOptions: { currency: 'USD' },
},
{
accessorKey: 'stock',
header: 'Stock',
cellDataType: 'number',
},
{
accessorKey: 'active',
header: 'Active',
cellDataType: 'boolean',
},
{
accessorKey: 'rating',
header: 'Rating',
cellDataType: 'rating',
cellDataTypeOptions: { max: 5 },
},
{
accessorKey: 'createdAt',
header: 'Created',
cellDataType: 'date',
cellDataTypeOptions: { format: 'PP' },
},
]
</script>
<template>
<NuGrid
:data="data"
:columns="columns"
:editing="{ enabled: true }"
/>
</template>