Skip to content

cristianm-developer/react-import-sheet-headless

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

25 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

@cristianmpx/react-import-sheet-headless

Headless React library for importing and validating Excel/CSV sheet data. No built-in table UI—you bring your own components; the library provides the logic and bulk validation.

npm version License: MIT

Installation

npm install @cristianmpx/react-import-sheet-headless

Peer dependencies: React 18+ (react and react-dom).

⚙️ Framework Setup

Good news: As of version 2.0.0, no special configuration is required! The library runs entirely on the main thread, so it works out-of-the-box with all bundlers (Vite, Webpack, Rollup, etc.) and frameworks (Next.js, Remix, etc.).

Why Headless

Bring your own components; we provide the logic and bulk validation. No prebuilt <Table />—you own the UI and the UX.

Pipeline

Data flows through a single pipeline on the main thread.

flowchart LR
  A[Input File] --> B[Parser]
  B --> C[Convert]
  C --> D[Sanitizer]
  D --> E[Validator]
  E --> F[Transform]
  F --> G[Sheet + Errors]
  G -.-> H[Edit optional]
Loading

Order: Input File → Parser → Convert → Sanitizer → Validator → Transform → Result (sheet) + Errors. Optional: cell-level edit on the result.

Quick Start

~10 lines to see the value: wrap with the provider, pick a file, read result and errors.

import {
  ImporterProvider,
  useImporter,
  useSheetView,
} from '@cristianm/react-import-sheet-headless';

const myLayout = { name: 'my-sheet', version: 1, fields: {} };

function App() {
  return (
    <ImporterProvider>
      <ImporterUI />
    </ImporterProvider>
  );
}

function ImporterUI() {
  const { processFile } = useImporter({ layout: myLayout });
  const { sheet, getPaginatedResult } = useSheetView({ defaultPageSize: 10 });

  if (!sheet) {
    return (
      <input
        type="file"
        accept=".csv,.xlsx"
        onChange={(e) => e.target.files?.[0] && processFile(e.target.files[0])}
      />
    );
  }

  const { rows } = getPaginatedResult(1, 10);
  return (
    <div>
      <p>
        Rows: {sheet.rows.length} | Errors: {sheet.errors.length}
      </p>
      {/* Your table component here, e.g. rows.map(...) */}
    </div>
  );
}

For layout, custom validators, and step-by-step usage, see How to / Usage. For a documented example (layout, fields, sanitizers, validators, transforms) with comments, see examples/ImportExample.md.

Virtualization (e.g. react-window)

Use totalRows and getRows(page, limit) (page is 1-based) from useSheetView() to feed a virtual list without loading all rows into the DOM:

import { FixedSizeList as List } from 'react-window';
import { useSheetView } from '@cristianm/react-import-sheet-headless';

function VirtualizedTable() {
  const { getRows, totalRows } = useSheetView({ filterMode: 'all' });
  const pageSize = 50;

  const Row = ({ index, style }: { index: number; style: React.CSSProperties }) => {
    const page = Math.floor(index / pageSize) + 1;
    const offset = index % pageSize;
    const chunk = getRows(page, pageSize);
    const row = chunk[offset];
    return <div style={style}>{row ? `Row ${row.index}: ${JSON.stringify(row.cells)}` : null}</div>;
  };

  return (
    <List height={400} itemCount={totalRows} itemSize={32} width="100%">
      {Row}
    </List>
  );
}

Persistence: When using persist={true}, call clearPersistedState() (from useSheetView) after the user has successfully submitted the import to your server, so data is not left in IndexedDB indefinitely. See View / Persist.

Error Handling

The library exposes errors through useSheetData().errors. Errors include both global errors (parser failures) and validation errors (cell/row/sheet level).

const { errors, sheet } = useSheetData();
const { status } = useImporterStatus();

if (status === 'error' && !sheet) {
  // Fatal error: parser failed before creating a sheet
  const fatalError = errors[0];
  console.error(`${fatalError.code}: ${fatalError.message}`);
  // Example: PARSER_FAILED, PARSER_NO_SHEETS
}

if (errors.length > 0) {
  // Validation errors or warnings
  errors.forEach((error) => {
    console.error(`Row ${error.rowIndex}, Cell ${error.cellKey}: ${error.message}`);
  });
}

Error codes reference: See Error Codes for a complete list of error codes, their meanings, and how to handle them.

How to (usage)

Step-by-step usage and recipes (handling large files, real-time errors, session recovery): How to / Usage.

Topic-specific guides: Parser, Convert, Sanitizer, Validators, Transformers, Edit, View, Result — convert to your object for submit.

Schema Docs

The sheet layout (SheetLayout) defines validators, sanitizers, and transformers by level (cell, row, sheet). Options and parameters are documented in:

Type Documentation
Validators Validators reference
Sanitizers Sanitizers reference
Transformers Transformers reference

By level:

To add or use controller modules (validators, sanitizers, transforms by context): Controllers.

Contributing

  • Conventional Commits: This project uses Conventional Commits (feat:, fix:, docs:, etc.). PRs that do not follow this convention may be asked to amend their commit messages.
  • Tests required: All contributions must pass the test suite. Run npm run test before opening a PR. Vitest is used; coverage is maintained. Pre-push hooks may run tests.

License and links

  • License: MIT
  • Repository: (add your repo URL)
  • Documentation: docs/

About

A high-performance, headless React library for spreadsheet imports. Features a multi-stage pipeline (Parser → Sanitizer → Validator → Transform) powered by Web Workers and Comlink for zero main-thread blocking.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors