NuGrid supports schema-based validation using any library that implements the Standard Schema specification, including Zod.
<script setup lang="ts">
import { z } from 'zod'
// Define your schema
const userSchema = z.object({
name: z.string().min(2, 'Name must be at least 2 characters'),
email: z.string().email('Please enter a valid email'),
age: z.number().int().min(18, 'Must be 18 or older').max(120),
salary: z.number().min(0, 'Salary must be positive'),
})
</script>
<template>
<NuGrid
:data="data"
:columns="columns"
:validation="{ schema: userSchema }"
:editing="{ enabled: true }"
/>
</template>
Configure validation behavior with an options object:
<script setup lang="ts">
const validationOptions = {
schema: userSchema,
validateOn: 'reward', // When to validate
showErrors: 'always', // When to show error messages
icon: 'i-lucide-alert-circle',
onInvalid: 'block', // What to do on invalid input
}
</script>
<template>
<NuGrid
:data="data"
:columns="columns"
:validation="validationOptions"
:editing="{ enabled: true }"
/>
</template>
| Option | Type | Default | Description |
|---|---|---|---|
schema | StandardSchema | - | Validation schema (Zod, Valibot, etc.) |
validateOn | 'submit' | 'blur' | 'change' | 'reward' | 'reward' | When to trigger validation |
showErrors | 'never' | 'hover' | 'always' | 'always' | When to display error messages |
icon | string | 'i-lucide-alert-circle' | Error icon |
onInvalid | 'block' | 'revert' | 'warn' | 'block' | Behavior on invalid input |
Add cross-field validation rules:
<script setup lang="ts">
const rowRules = [
// Engineering department requires salary >= $100k
(row: User) => {
if (row.department === 'Engineering' && row.salary < 100000) {
return {
valid: false,
message: 'Engineering employees must have salary >= $100,000',
failedFields: ['salary'],
}
}
return { valid: true }
},
// Manager role requires age >= 25
(row: User) => {
if (row.role === 'Manager' && row.age < 25) {
return {
valid: false,
message: 'Managers must be at least 25 years old',
failedFields: ['age'],
}
}
return { valid: true }
},
]
const validationOptions = {
schema: userSchema,
rowRules,
}
</script>
<script setup lang="ts">
import type { NuGridColumn, NuGridValidationOptions } from '#nu-grid/types'
import { z } from 'zod'
interface User {
id: number
name: string
email: string
age: number
department: string
salary: number
}
const data = ref<User[]>([
{ id: 1, name: 'Alice', email: 'alice@example.com', age: 28, department: 'Engineering', salary: 95000 },
{ id: 2, name: 'Bob', email: 'bob@example.com', age: 35, department: 'Marketing', salary: 65000 },
])
// Zod schema
const userSchema = z.object({
id: z.number(),
name: z.string().min(2).max(50),
email: z.string().email(),
age: z.number().int().min(18).max(120),
department: z.string().min(1),
salary: z.number().min(0),
})
// Row validation rules
const rowRules = [
(row: User) => {
if (row.department === 'Engineering' && row.salary < 100000) {
return {
valid: false,
message: 'Engineering salary must be >= $100k',
failedFields: ['salary'],
}
}
return { valid: true }
},
]
const validationOptions: NuGridValidationOptions<User> = {
schema: userSchema,
rowRules,
validateOn: 'reward',
showErrors: 'always',
onInvalid: 'block',
}
const columns: NuGridColumn<User>[] = [
{ accessorKey: 'id', header: 'ID', enableEditing: false },
{ accessorKey: 'name', header: 'Name' },
{ accessorKey: 'email', header: 'Email' },
{ accessorKey: 'age', header: 'Age' },
{ accessorKey: 'department', header: 'Department' },
{
accessorKey: 'salary',
header: 'Salary',
cell: ({ row }) => `$${row.original.salary.toLocaleString()}`,
},
]
</script>
<template>
<NuGrid
:data="data"
:columns="columns"
:validation="validationOptions"
:editing="{ enabled: true, startClicks: 'double' }"
:focus="{ retain: true }"
/>
</template>