ExcelImport API
Description
ExcelImport component for Gantt that imports tasks from Excel (.xlsx) and CSV files with column-to-field mappingA standalone modal wizard that converts a spreadsheet into Gantt-ready JSON. The user uploads an Excel (.xlsx) or CSV file and maps its columns to task fields; the widget returns an array of task objects through onimport, which you then load into Gantt. Render the component conditionally, it opens the modal on mount.
The widget ships as a separate package. Install it alongside Gantt and import the component from @svar-ui/svelte-excel-import:
npm install @svar-ui/svelte-excel-import
Usage
interface ImportWizardConfig {
// fields to map spreadsheet columns to (the Gantt task fields)
fields: FieldDefinition[];
// called with the parsed rows and a summary when the user confirms the import
onimport: (rows: TransformedRow[], result: ImportResult) => void;
// called when the wizard should close
onclose?: () => void;
// validates the current column-to-field mapping
validate?: (
mappings: FieldMappings,
data: ParsedSheetData
) => ValidationResult;
// pre-parsed data; when set, the upload step is skipped
data?: ParsedExcelData;
// accepted file types for the file picker
accept?: string;
// number of rows shown in the mapping preview; default: 10
previewRowCount?: number;
// auto-detect the column-to-field mapping; default: true
autoDetection?: boolean;
// treat the first row as a header; default: true
headerRow?: boolean;
// close the wizard right after import, skipping the result screen; default: false
autoClose?: boolean;
// generate a unique id for rows that don't have one; default: false
generateIds?: boolean;
// placement of the mapping selectors; default: "both"
selectors?: "top" | "right" | "both";
}
interface FieldDefinition {
id: string;
label: string;
required?: boolean;
expectedType?: "text" | "number" | "date" | "boolean" | "mixed";
keywords?: string[];
}
Parameters
The configuration is passed to the component as props:
fields- (required) the list of fields a column can be mapped to. Each field maps to a Gantt task property (text,start,duration, etc.). See FieldDefinition below.onimport- (required) called when the user confirms the import. Receivesrows(an array of objects keyed by fieldid, with values converted to native types) andresult(an import summary).onclose- (optional) called when the wizard should close (cancel button, overlay click, or after import).validate- (optional) a function that checks the current mapping and returns a validation result. Receives the field-to-columnmappingsand the parsed sheetdata. Blocking errors prevent the import; warnings are shown but allow it.data- (optional) pre-parsed file data. When provided, the wizard skips the upload step and opens directly on the mapping screen.accept- (optional) theacceptattribute for the file picker, restricting selectable file types.previewRowCount- (optional) the number of data rows shown in the mapping preview. Default:10.autoDetection- (optional) whentrue, columns are matched to fields automatically using headers andkeywords. Default:true.headerRow- (optional) whentrue, the first row is treated as a header. Set tofalsefor files without headers: the first row becomes data and columns get generic labels (Column A,Column B, ...). Default:true.autoClose- (optional) whentrue, the wizard closes immediately after import, skipping the result screen. Default:false.generateIds- (optional) whentrue, a unique numericidis assigned to every imported row that doesn't already have one. Default:false.selectors- (optional) where the column-mapping selectors are placed. Default:"both"."top"- selectors above the preview columns"right"- selectors in a side panel"both"- both placements
FieldDefinition
| Field | Type | Description |
|---|---|---|
id | string | Unique field id. Use the target Gantt task property name (text, start, duration, ...). |
label | string | Display label shown in the mapping UI. |
required | boolean | When true, the field must be mapped; rows with an empty value are skipped and reported in the result. |
expectedType | "text" | "number" | "date" | "boolean" | "mixed" | Filters out rows whose value doesn't match the type. It does not change the output type. |
keywords | string[] | Extra hints used by auto-detection to match a column to this field. |
ImportResult
The second argument of onimport.
| Field | Type | Description |
|---|---|---|
imported | number | Number of rows successfully imported. |
skipped | number | Number of rows skipped due to errors. |
errors | Array<{ row: number; reason: string }> | Per-row reasons for skipped rows. |
ValidationResult
Returned by validate.
| Field | Type | Description |
|---|---|---|
valid | boolean | Whether the import can proceed. |
errors | ValidationError[] | Blocking errors; each has fieldId, message, and code. |
warnings | ValidationWarning[] | Non-blocking warnings; each has type, message, and an optional fieldId/columnId. |
Example
The example below maps spreadsheet columns to Gantt task fields and loads the result into Gantt. Props are passed individually, and ExcelImport is rendered only while the wizard is open.
<script>
import { Gantt } from "@svar-ui/svelte-gantt";
import { ExcelImport } from "@svar-ui/svelte-excel-import";
import { Button } from "@svar-ui/svelte-core";
const taskFields = [
{ id: "id", label: "ID", keywords: ["id", "identifier"] },
{ id: "text", label: "Task name", keywords: ["name", "title", "task"] },
{ id: "start", label: "Start date", expectedType: "date", required: true },
{ id: "end", label: "End date", expectedType: "date" },
{ id: "duration", label: "Duration", expectedType: "number" },
{ id: "progress", label: "Progress", expectedType: "number" },
{ id: "type", label: "Type" },
{ id: "parent", label: "Parent ID" },
];
let showImport = $state(false);
let tasks = $state([]);
function handleImport(rows, result) {
tasks = rows.map(row => {
const task = {
id: row.id,
text: row.text,
type: row.type || "task",
progress: row.progress ?? 0,
parent: row.parent || 0,
};
if (row.start instanceof Date) task.start = row.start;
if (row.end instanceof Date) task.end = row.end;
if (row.duration != null) task.duration = row.duration;
if (task.type === "summary") task.open = true;
return task;
});
showImport = false;
}
</script>
<Button type="primary" onclick={() => (showImport = true)}>
Import tasks
</Button>
<Gantt {tasks} />
{#if showImport}
<ExcelImport
fields={taskFields}
onimport={handleImport}
onclose={() => (showImport = false)}
autoClose={true}
/>
{/if}
Related articles: