Schema Validation

Spreadsheet Validator uses Zod to define validation schemas for your spreadsheet columns. Each key in the schema maps to a column header in the file.

Defining a Schema

Create a Zod object schema where each key matches a column header (case-sensitive):

import { z } from "zod"

const employeeSchema = z.object({
  name: z.string().min(1, "Name is required"),
  email: z.string().email("Invalid email address"),
  department: z.enum(["Engineering", "Marketing", "Sales", "HR"]),
  salary: z.number().positive("Salary must be positive"),
})

Then pass it to the TableReader:

<TableReader file={file} schema={employeeSchema} />

How Validation Works

  1. The file is parsed into rows of data
  2. The Zod schema is converted to JSON schema and sent to a Web Worker
  3. The worker runs safeParse() on each row
  4. Errors are mapped back to specific cells (row + column)
  5. Invalid rows are displayed first with red-highlighted cells

Column Detection

If a column in your spreadsheet doesn't exist in the schema, the header is highlighted in red. This helps identify:

  • Typos in column names
  • Extra columns not expected by the schema
  • Missing required columns

Date Handling

For date columns, use z.iso.date() or z.iso.datetime() instead of z.date(). The z.date() type expects a JavaScript Date instance, which doesn't work well with spreadsheet data parsed as strings.

const schema = z.object({
  name: z.string(),
  // Use z.iso.date() for date columns
  startDate: z.iso.date(),
  // Or z.iso.datetime() for datetime columns
  createdAt: z.iso.datetime(),
})

Warning: Using z.date() is not recommended and may cause unexpected validation errors, since spreadsheet values are parsed as strings, not Date objects.

The library automatically converts Excel date serial numbers to ISO date strings. Supported display formats:

  • DD/MM/YYYY (default)
  • YYYY-MM-DD
  • DD/MM/YY
  • MM/DD/YYYY

Error Callbacks

Use the errorIssuesLog callback to receive all validation errors:

<TableReader
  file={file}
  schema={schema}
  errorIssuesLog={(errors) => {
    if (errors) {
      errors.forEach((err) => {
        console.log(`Row ${err.rowIndex}, Column ${err.column}: ${err.message}`)
      })
    }
  }}
/>

Each error extends Zod's $ZodIssue with additional column and rowIndex properties.

Valid Data Callback

Use onTableData to receive only the rows that passed validation:

<TableReader
  file={file}
  schema={schema}
  onTableData={(validRows) => {
    console.log(`${validRows.length} rows are valid`)
    // Send to API, save to state, etc.
  }}
/>

Next Steps

Learn about File Upload handling and supported file types.