Skip to content

Loading Data

Type (onChunk: (rows: TRow[], options?: ChunkSourceOptions) => void) => Promise<void>

Async function that feeds data into the editor. Called once when the editor opens. Call onChunk one or more times to stream rows in batches. The editor processes each chunk without blocking the UI.

Rows you pass are filled out to your schema: a column missing from a row gains an empty cell so every row has the same keys. Values you did pass are kept exactly as they are — a null stays null until someone edits that cell.

loadData={async (onChunk) => {
const res = await fetch("/api/employees");
const rows = await res.json();
onChunk(rows);
}}

Tag chunks with a data source to keep data from different origins apart. The editor registers a source the first time it sees one.

loadData={async (onChunk) => {
const [sf, hs] = await Promise.all([fetchSalesforce(), fetchHubspot()]);
onChunk(sf.chunk1, { source: "Salesforce" });
onChunk(sf.chunk2, { source: "Salesforce", done: true });
onChunk(hs.data, { source: "HubSpot", deletable: true, done: true });
}}

Chunks without options go to “Existing Data”. You can mix tagged and untagged chunks freely.

Typed columns canonicalize the strings you send, the same way an import does.

Each column is read on its own. The SDK scores every shape it knows against the values of that column and takes the one that explains the most of them, so a column of 13/05/2026 reads day first and a column of 05/13/2026 reads month first even when both arrive in the same chunk. A value the winning shape cannot explain stays text and its cell is flagged.

A column whose values never separate two shapes falls to the browser locale, and the SDK reports the column through onError so you can see which one it was. Send ISO dates and plain 1234.56 numbers to settle it yourself.

The verdict belongs to the source and the column together. The first chunk that carries a signal fixes the reading of that column, later chunks of that source follow it, and a chunk tagged with a different source starts its own.

A multiselect column splits a delimited string into tokens: "red, blue" arrives as ["red", "blue"]. An array you send passes through untouched, and an empty string becomes an empty list. The delimiter comes from editor.delimiter when declared.

Field Type Default Description
source string Display name for the data source. When omitted, the chunk goes to “Existing Data”.
id string source value Stable identifier.
deletable boolean false Whether the user can delete this source from the editor.
done boolean false Marks this source as finished loading. Shows a completion state in the UI.
changes InitialRowChange[] Seed previous edit state for rows in this chunk. See Seeding previous changes.
  • The first onChunk call with a new source registers it and starts its loading indicator.
  • Set done: true to mark a source as finished. You can send an empty chunk: onChunk([], { source: "CRM", done: true }).
  • When the loadData promise resolves, the editor finalizes every source still loading.

Resume a previous editing session by passing change descriptors alongside rows. The editor opens with the diff already visible.

loadData={async (onChunk) => {
const rows = await fetchCurrentState();
onChunk(rows, {
changes: [
{ index: 2, originalValues: { name: "John" } },
{ index: 5, isNew: true },
{ index: 8, isDeleted: true },
]
});
}}
Field Type Description
index number Index of this row within the chunk’s rows array.
originalValues Partial<TRow> Original field values before edits. Only fields that differ. Marks the row as edited.
isNew boolean Row was added in a previous session.
isDeleted boolean Row is pending deletion.

Flags can be combined. Seeded changes are the session baseline (not undoable). Reverting a cell to its original value clears the edited flag. onComplete returns deltas relative to the original data. The SDK does not persist changes between sessions.

Type Record<string, unknown>[]

Sample rows for the “Download Example” file. When the user clicks that button in the import wizard, the SDK generates a template carrying your column headers and these rows.

When omitted, the SDK generates one generic example row from your column definitions.

sampleData={[
{ name: "Jane Smith", email: "[email protected]", role: "Admin" },
{ name: "John Doe", email: "[email protected]", role: "Editor" },
]}