Skip to content

Cell Validation

ValidationEngine provides four rule types for validating cell values. Rules can be set at the column level (apply to all cells in the column) or at the individual cell level. When both exist, they are combined and the first failure is returned. Invalid cells display error tooltips on hover via TooltipManager.

Live Demo
Row 2 has invalid email and negative age. Row 3 has missing email, age >150, and salary warning. Hover over error cells to see tooltips.
View source code
ValidationDemo.tsx
import { WitTable } from '@witqq/spreadsheet-react';
import type { ColumnDef } from '@witqq/spreadsheet';
import { DemoWrapper } from './DemoWrapper';
import { useSiteTheme } from './useSiteTheme';
const columns: ColumnDef[] = [
{ key: 'name', title: 'Name', width: 160, validation: [{ type: 'required', message: 'Name is required', severity: 'error' }] },
{ key: 'email', title: 'Email', width: 200, validation: [{ type: 'required', message: 'Email is required', severity: 'error' }, { type: 'regex', pattern: '^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$', message: 'Invalid email format', severity: 'error' }] },
{ key: 'age', title: 'Age', width: 80, type: 'number', validation: [{ type: 'range', min: 0, max: 150, message: 'Age must be 0-150', severity: 'error' }] },
{ key: 'salary', title: 'Salary', width: 100, type: 'number', validation: [{ type: 'range', min: 0, max: 1000000, message: 'Salary must be 0-1M', severity: 'warning' }] },
{ key: 'department', title: 'Department', width: 130 },
];
const data = [
{ name: 'Alice Smith', email: 'alice@example.com', age: 30, salary: 75000, department: 'Engineering' },
{ name: '', email: 'invalid-email', age: -5, salary: 50000, department: 'Sales' },
{ name: 'Carol Brown', email: '', age: 200, salary: 2000000, department: 'HR' },
{ name: 'David Jones', email: 'david@example.com', age: 45, salary: 90000, department: 'Finance' },
{ name: '', email: '', age: 0, salary: 0, department: '' },
];
export function ValidationDemo() {
const { witTheme } = useSiteTheme();
return (
<DemoWrapper title="Live Demo" description="Row 2 has invalid email and negative age. Row 3 has missing email, age >150, and salary warning. Hover over error cells to see tooltips." height={300}>
<WitTable
theme={witTheme}
columns={columns}
data={data}
showRowNumbers
editable
style={{ width: '100%', height: '100%' }}
/>
</DemoWrapper>
);
}
TypeDescriptionExample
requiredCell must have a non-empty valueRequired field
rangeNumeric value must be within min/maxPrice between 0 and 10000
regexValue must match a regular expressionEmail format
customCustom validation functionCross-field validation

Each rule has a severity level: error, warning, or info.

import { WitTable } from '@witqq/spreadsheet-react';
const columns: ColumnDef[] = [
{
key: 'name',
title: 'Name',
editable: true,
validation: [
{ type: 'required', message: 'Name is required', severity: 'error' },
],
},
{
key: 'email',
title: 'Email',
editable: true,
validation: [
{ type: 'required', message: 'Email is required', severity: 'error' },
{ type: 'regex', pattern: /^[^\s@]+@[^\s@]+\.[^\s@]+$/, message: 'Invalid email', severity: 'error' },
],
},
{
key: 'age',
title: 'Age',
type: 'number',
editable: true,
validation: [
{ type: 'range', min: 0, max: 150, message: 'Age must be 0-150', severity: 'error' },
],
},
];
function App() {
return <WitTable columns={columns} data={data} editable={true} />;
}
const ve = ref.current?.getInstance().getValidationEngine();
// Set column-level rules
ve.setColumnRules(1, [
{ type: 'required', message: 'Required', severity: 'error' },
]);
// Set cell-level rules
ve.setCellRules(0, 2, [
{ type: 'custom', validate: (value) => value > 0, message: 'Must be positive', severity: 'warning' },
]);
// Validate a specific cell
const result = ve.validateCell(0, 1);
// { valid: false, message: 'Required', severity: 'error' }
MethodSignatureDescription
setColumnRules(col: number, rules: WitValidationRule[]) => voidSet column validation
setCellRules(row: number, col: number, rules: WitValidationRule[]) => voidSet cell validation
validateCell(row: number, col: number) => ValidationResultValidate single cell
validate(row: number, col: number, value: CellValue) => ValidationResultValidate value against rules
type WitValidationRule =
| { type: 'required'; message: string; severity: Severity }
| { type: 'range'; min?: number; max?: number; message: string; severity: Severity }
| { type: 'regex'; pattern: RegExp; message: string; severity: Severity }
| { type: 'custom'; validate: (value: unknown) => boolean; message: string; severity: Severity };
type Severity = 'error' | 'warning' | 'info';