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
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.
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
| Option | Type | Default | Description |
|---|---|---|---|
schema | CsvSchema | — | 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 |
maxFileSize | number | 10485760 (10 MB) | Maximum allowed file size in bytes |
Return Value
| Property | Type | Description |
|---|---|---|
open | () => void | Function to programmatically open the importer drawer |
props | CsvImporterProps | Props 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.
<CsvImporter {...props} />Schemas
CsvSchema
type CsvSchema = {
columns: CsvColumn[];
};CsvColumn
| Property | Type | Default | Description |
|---|---|---|---|
key | string | — | Internal key; becomes the object key in parsed row data |
label | string | — | Display label shown in the mapping UI |
description | string | — | Optional hint shown in the mapping UI |
required | boolean | false | Whether this column must be mapped before proceeding |
aliases | string[] | — | Alternative CSV header names for automatic matching |
schema | StandardSchemaV1 | — | 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.
| Helper | Output type | Description |
|---|---|---|
csv.string(options?: { min?: number; max?: number }) | string | Pass-through string with optional length constraints |
csv.number(options?: { min?: number; max?: number; integer?: boolean }) | number | Coerces raw CSV string to a number; rejects NaN |
csv.boolean(options?: { truthy?: string[]; falsy?: string[] }) | boolean | Recognises "true"/"1"/"yes" and "false"/"0"/"no" (case-insensitive) |
csv.date() | Date | Coerces raw CSV string to a Date; rejects unparseable values |
csv.enum(values: string[]) | T extends string | Validates the value is one of the allowed strings (case-sensitive) |
// 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.
const { open, props } = useCsvImporter({
schema: { columns: [...] },
onValidate: async (rows) => {
const issues = await checkUniqueness(rows);
return issues; // CsvCellIssue[]
},
onImport: (event) => { /* ... */ },
});CsvCellIssue
| Property | Type | Description |
|---|---|---|
rowIndex | number | 0-based row index |
columnKey | string | The schema column key |
level | "error" | "warning" | "error" blocks import; "warning" allows import |
message | string | Human-readable message displayed inline in the table |
Import Event
The onImport callback receives a CsvImportEvent with the following shape:
| Property | Type | Description |
|---|---|---|
file | File | The original file selected by the user |
mappings | CsvColumnMapping[] | The confirmed column mappings |
corrections | CsvCorrection[] | Corrections made by the user in the review step |
issues | CsvCellIssue[] | 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.
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.