Skip to content
View as Markdown

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
schemaCsvSchema—Column 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
keystring—Internal key; becomes the object key in parsed row data
labelstring—Display label shown in the mapping UI
descriptionstring—Optional hint shown in the mapping UI
requiredbooleanfalseWhether this column must be mapped before proceeding
aliasesstring[]—Alternative CSV header names for automatic matching
schemaStandardSchemaV1—Standard 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