Skip to content

CsvImporter

The CsvImporter component provides a guided, multi-step CSV import flow rendered inside a drawer. It handles drag-and-drop file upload, interactive column mapping, Standard Schema validation, inline cell editing, and async server-side validation.

Import

tsx
import {
  CsvImporter,
  useCsvImporter,
  csv,
  type CsvSchema,
  type CsvColumn,
  type CsvImportEvent,
  type CsvCellIssue,
  type CsvCorrection,
  type CsvColumnMapping,
  type ParsedRow,
  type InferCsvRow,
} from "@tailor-platform/app-shell";

Basic Usage

Use the useCsvImporter hook to manage state, then render <CsvImporter> with the returned props.

tsx
import { CsvImporter, useCsvImporter, csv } from "@tailor-platform/app-shell";
import { Button } from "@tailor-platform/app-shell";

function ProductImport() {
  const { open, props } = useCsvImporter({
    schema: {
      columns: [
        {
          key: "name",
          label: "Name",
          required: true,
          aliases: ["product_name"],
          schema: csv.string({ min: 1 }),
        },
        {
          key: "price",
          label: "Price",
          schema: csv.number({ min: 0 }),
        },
        {
          key: "active",
          label: "Active",
          schema: csv.boolean(),
        },
      ],
    },
    onImport: (event) => {
      console.log(event.summary);
    },
  });

  return (
    <>
      <Button onClick={open}>Import CSV</Button>
      <CsvImporter {...props} />
    </>
  );
}

useCsvImporter

The useCsvImporter hook manages the open/close state and returns both an open function and props to spread onto <CsvImporter>.

Options

OptionTypeDefaultDescription
schemaCsvSchemaColumn definitions for the import (see CsvSchema)
onImport(event: CsvImportEvent) => void | Promise<void>Called when the user confirms the import after resolving all errors
onValidate(rows: ParsedRow[]) => Promise<CsvCellIssue[]>Optional async callback for server-side validation after schema checks pass
maxFileSizenumber10485760 (10 MB)Maximum allowed file size in bytes

Return Value

PropertyTypeDescription
open() => voidFunction to programmatically open the importer drawer
propsCsvImporterPropsProps object to spread directly onto <CsvImporter>

CsvImporter Props

CsvImporter is intended to be used with props returned from useCsvImporter. Spread the props object directly onto the component.

tsx
<CsvImporter {...props} />

Schemas

CsvSchema

ts
type CsvSchema = {
  columns: CsvColumn[];
};

CsvColumn

PropertyTypeDefaultDescription
keystringInternal key; becomes the object key in parsed row data
labelstringDisplay label shown in the mapping UI
descriptionstringOptional hint shown in the mapping UI
requiredbooleanfalseWhether this column must be mapped before proceeding
aliasesstring[]Alternative CSV header names for automatic matching
schemaStandardSchemaV1Standard Schema validator for coercion and validation (see csv helpers)

csv Helpers

Built-in Standard Schema validators for common CSV column types. Each helper handles both coercion and validation in a single declaration.

HelperOutput typeDescription
csv.string(options?: { min?: number; max?: number })stringPass-through string with optional length constraints
csv.number(options?: { min?: number; max?: number; integer?: boolean })numberCoerces raw CSV string to a number; rejects NaN
csv.boolean(options?: { truthy?: string[]; falsy?: string[] })booleanRecognises "true"/"1"/"yes" and "false"/"0"/"no" (case-insensitive)
csv.date()DateCoerces raw CSV string to a Date; rejects unparseable values
csv.enum(values: string[])T extends stringValidates the value is one of the allowed strings (case-sensitive)
tsx
// String with required check (min: 1)
csv.string({ min: 1 });

// Number with lower bound
csv.number({ min: 0 });

// Integer only
csv.number({ integer: true });

// Boolean with defaults: truthy = ["true","1","yes"], falsy = ["false","0","no"]
csv.boolean();

// Date
csv.date();

// Enum
csv.enum(["active", "inactive", "pending"]);

Server-side Validation

Use onValidate to perform async checks (e.g. uniqueness constraints) after schema validation passes. Return an array of CsvCellIssue objects to mark cells with errors or warnings.

tsx
const { open, props } = useCsvImporter({
  schema: { columns: [...] },
  onValidate: async (rows) => {
    const issues = await checkUniqueness(rows);
    return issues; // CsvCellIssue[]
  },
  onImport: (event) => { /* ... */ },
});

CsvCellIssue

PropertyTypeDescription
rowIndexnumber0-based row index
columnKeystringThe schema column key
level"error" | "warning""error" blocks import; "warning" allows import
messagestringHuman-readable message displayed inline in the table

Import Event

The onImport callback receives a CsvImportEvent with the following shape:

PropertyTypeDescription
fileFileThe original file selected by the user
mappingsCsvColumnMapping[]The confirmed column mappings
correctionsCsvCorrection[]Corrections made by the user in the review step
issuesCsvCellIssue[]Any remaining issues (warnings only — errors are resolved before import)
summary{ totalRows, validRows, correctedRows, skippedRows, warningRows }Summary statistics
buildRows()() => Promise<InferCsvRow<T>[]>Reconstruct fully-processed rows with schema coercion and corrections

event.buildRows()

A method on the import event that reconstructs the fully processed row data on the client side. The return type is inferred from the schema definition — column keys become object keys, and StandardSchemaV1 output types are preserved.

tsx
onImport: async (event) => {
  const rows = await event.buildRows();
  // rows is typed based on schema — e.g. { name: string; price: number; ... }[]
  await saveToBackend(rows);
},

If you are sending the file, mappings, and corrections to a backend for processing, you do not need buildRows().

i18n

CsvImporter includes built-in English and Japanese labels. No additional setup is required.

  • Sheet — Slide-in panel (the drawer used internally by CsvImporter)
  • Button — Use as the trigger to open the importer