Options
Required
importerKey: string
This can be found in the admin panel.
importerKey: "your-importer-key";
Optional
user: json object
Contains details of the user, so that they can be identified when your backend receives a webhook.
user: {
userId: "12345";
}
metadata: json object
If you have additional data which you want to associate with the import but isn't related to the user, you can use the metadata
prop. This will also be included in the webhook your backend receives.
metadata: { anotherId: "123" }
downloadExampleButton: boolean
Choose if you want to display the Download Example
button found in the first Getting Started step in the importer.
Default value is true
sampleFileURL: string
Used to set your sample file URL that will be downloaded when clicking the Download Example
button found in the first Getting Started step in the importer.
defaultLanguage: enum
type Language = "en" | "fr" | "es" | "pt" | "de" | "nl" | "it";
Used to set the importer default language. defaultLanguage
option has a higher priority than the default language set in the admin panel.
acceptedFileFormats: array
type acceptedFileFormats = Array<"xls" | "xlsx" | "xlsb" | "csv">;
Used to set accepted file formats. The default value is ["csv", "xls", "xlsx", "xlsb"]
columnWidth: enum
type columnWidth = "fixed" | "auto";
Used to set column width in the Match Columns table. Kindly note that choosing the auto
option might affect the column matching step perforamce. Default value is fixed
.
customText: json object
Used to set custom text messages in the importer.
type customText = {
importedRows: {
text: string | undefined;
downloadRowsButton: string | undefined;
} | undefined;
rejectedRows: {
text: string | undefined;
downloadRowsButton: string | undefined;
} | undefined;
}
- importedRows:
- text: a custom message for successfully imported rows. Default is
{{rows_count}} rows were imported successfully
. Use{{rows_count}}
placeholder to show the number of imported rows. - downloadRowsButton: a custom text for the download imported rows button. Default is
Download .csv with imported rows
- text: a custom message for successfully imported rows. Default is
- rejectedRows:
- text: a custom message for rejected rows. Default is
{{rows_count}} rows have errors and were not imported
. Use{{rows_count}}
placeholder to show the number of rejected rows. - downloadRowsButton: a custom text for the download rejected rows button. Default is
Download .csv with rows that were not imported
- text: a custom message for rejected rows. Default is
batchSize: number
batchSize
option is used to adjust the number of rows per batch sent to:
Please note that using batchSize
option requires a different response format in onData callback
If batchSize
is not used, the default behaviour will apply:
- onRecordsInitial Validation Hook will receive 1,000 rows per batch.
- onData callback will receive all rows in one batch (no batching).
- Webhook will receive 1,000 rows per batch.
// usage example
var importButton = document.getElementById("import-data-button");
importButton.onclick = function () {
useCsvPlugin({
importerKey: "your-importer-key",
batchSize: 20, // 20 rows per batch will be sent to onRecordsInitial Validation Hook, onData callback and Webhook
});
};
dynamicColumns: array of json objects
dynamicColumns
option is used to define your importer columns.
Ways to define importer columns:
- From the admin panel.
- From the frontend using the
dynamicColumns
option. - Using both ways combined.
dynamicColumns
type and definition
type DynamicColumnsType = Array<{
name: string;
displayName?: string | null | undefined;
description?: string | null | undefined;
example?: string | null | undefined;
mustBeMatched?: boolean | null | undefined;
valueCannotBeBlank?: boolean | null | undefined;
validationHook?: boolean | null | undefined;
customValidationErrorMessage?: string | null | undefined;
validationFormat:
| { type: "string" }
| { type: "number" }
| { type: "date"; format: DateFormatsType }
| { type: "phone" }
| { type: "email"; format?: "allowDisplayName" | null | undefined }
| { type: "regex"; format: string }
| { type: "select"; format: string }
| { type: "boolean"; format: BooleanFormatsType };
}>;
type BooleanFormatsType = "true,false" | "yes,no" | "1,0";
type DateFormatsType =
| "DD/MM/YYYY"
| "DD/MM/YY"
| "DD-MM-YYYY"
| "DD-MM-YY"
| "DD.MM.YYYY"
| "DD.MM.YY"
| "MM/DD/YYYY"
| "MM/DD/YY"
| "MM-DD-YYYY"
| "MM-DD-YY"
| "MM.DD.YYYY"
| "MM.DD.YY"
| "YYYY-MM-DD"
| "DATEVALUE";
name
: required string to define column's name.displayName
: optional string, users will see this name when using the Importer. If you leave this blank, we will use the column name.description
: optional string to define column's description.mustBeMatched
: optional boolean to define if column must be matched to a column in the imported data.valueCannotBeBlank
: optional boolean to define if cell value cannot be blank.validationHook
: optional boolean to define if data in this column will be sent to Validation Hooks callback functions.customValidationErrorMessage
: optional boolean to define a custom error to show users when their data does not meet the validation format.validationFormat
: required json object:- type: string | number | date | phone | email | regex
- format: required for types date, regex, select and boolean and optional for type email.
- type regex: format is required to define your Custom Regular Expression.
{type: "regex", format: "^[\w.\-]+(@mydomain).com$"}
- type date: format is required to define your date format.
{type: "date", format: "DD-MM-YYYY"}
- type select: format is required to define your comma separated options.
{type: "select", format: "blue,red,yellow,white"}
- type boolean: format is required to define your comma separated templates.
{type: "boolean", format: "true,false"}
- type email: format is optional to allow display name.
{type: "email", format: "allowDisplayName"}
- type regex: format is required to define your Custom Regular Expression.
// usage example
var importButton = document.getElementById("import-data-button");
importButton.onclick = function () {
useCsvPlugin({
importerKey: "your-importer-key",
dynamicColumns: [
{
name: "firstName",
displayName: "First Name",
example: "jane",
mustBeMatched: true,
valueCannotBeBlank: true,
validationFormat: { type: "string" },
},
{
name: "lastName",
example: "smith",
mustBeMatched: true,
validationFormat: { type: "string" },
},
{
name: "email",
example: "jane@example.com",
description: "Must be a valid email address",
mustBeMatched: true,
valueCannotBeBlank: true,
validationFormat: { type: "email" },
},
{
name: "age",
example: "32",
validationFormat: { type: "number" },
customValidationErrorMessage: "Age must be a number",
},
],
});
};
onFileUpload: function
A function that is triggered when a file is uploaded in the importer.
type onFileUpload = (({ file }: { file: File }) => void) | undefined;
onMatchColumns: function
A function that is triggered when the Match Columns step is first loaded. Used to return a suggested column matching map.
type onMatchColumns = ({
configuredColumns,
uploadedFileHeaders,
headerRow,
}: {
configuredColumns: string[];
uploadedFileHeaders: string[];
headerRow: boolean;
}) => Promise<Record<string, string | undefined>> | Record<string, string | undefined> | undefined | void;
onMatchColumns
function parameters
configuredColumns
: array of configured columns, either from the admin panel or the dynamic columns option.uploadedFileHeaders
: array of column headers from the uploaded file. The value is an array of alphabet letters if the header row is absent (e.g, ['A', 'B', 'C', 'D', ...]).headerRow
boolean value that indicates if a header row exists in the uploaded file.
onMatchColumns
function response
Return a suggested column matching map formed as an object with keys of headers from the uploaded file and values of configured columns. UseCSV fuzzy matching is off when a column matching map is returned. Returning an empty object, undefined, or void enables UseCSV fuzzy matching.
// usage example
var importButton = document.getElementById("import-data-button");
importButton.onclick = function () {
useCsvPlugin({
importerKey: "your-importer-key",
onMatchColumns: ({ configuredColumns, uploadedFileHeaders, headerRow }) => {
console.log({ configuredColumns, uploadedFileHeaders, headerRow });
// configuredColumns = ['first_name', 'email_address']
// uploadedFileHeaders = ['name', 'email', 'age']
// headerRow = true
return {
name: "first_name",
email: "email_address",
age: undefined, // not matched
}
// return undefined or empty object to enable UseCSV fuzzy matching
},
});
};
onClose: function
A function that is triggered when the importer modal is closed.
// usage example
var importButton = document.getElementById("import-data-button");
importButton.onclick = function () {
useCsvPlugin({
importerKey: "your-importer-key",
onClose: () => {
console.log("Importer modal is closed");
},
});
};
onError: function
A function that is triggered when one of following errors occurs during the importing process.
- wrong_file_format: when a file is uploaded with wrong format.
- file_exceeds_rows_limit: when a file is uploaded with number of rows exceeding the plan limit.
- upload_limit_reached: when an attempt to upload a file is made after reaching the plan limit.
- Any error occurs during sending data to your webhook endpoint.
onError?: ({
importerId,
uploadId,
user,
metadata,
error,
}: {
importerId: string;
uploadId?: string;
user?: Record<string, string | number> | null;
metadata?: Record<string, string | number> | null;
error: string;
}) => void;
onError
function parameters
importerId
: importer ID.uploadId
: upload ID if an upload is made.user
json object of user object if provided.metadata
json object of metadata object if provided.error
: string
// usage example
var importButton = document.getElementById("import-data-button");
importButton.onclick = function () {
useCsvPlugin({
importerKey: "your-importer-key",
onError: ({importerId, uploadId, user, metadata, error}) => {
console.log({ error });
},
});
};
importerDisplay: inline | modal
Choose how to display your importer in frontend:
- modal: the default display.
- inline: displays the importer as an inline element to a parent element with id
usecsv-importer-inline-wrapper
andposition: relative;
. You can custom style the parent element and set width and height for the importer.
// _index.html_
// example of using inline display
<html>
<head>
<title>UseCSV</title>
<meta charset="UTF-8" />
</head>
<style>
#usecsv-importer-inline-wrapper {
position: relative;
border: 1px solid #027ad6;
width: 1200px;
height: 650px;
margin-top: 20px;
margin-left: auto;
margin-right: auto;
}
</style>
<body>
<div>
<h1>Start importing your data</h1>
<button type="button" id="import-data-button" onclick="importData()">
Import Data
</button>
{/* element with id usecsv-importer-inline-wrapper is required */}
<div id="usecsv-importer-inline-wrapper" />
</div>
<script src="index.js"></script>
</body>
</html>
// _index.js_;
import useCsvPlugin from "@usecsv/js";
function importData() {
useCsvPlugin({
importerKey: "your-importer-key",
user: { userId: "12345" },
importerDisplay: "inline",
});
}
theme: json object
You can edit each CSS property in the UseCSV default theme object, and pass it to the theme
option. Visit Theme Your Importer to know more about the theme
object.
onData: function
If you prefer to handle your data locally and disable uploading user data to UseCSV server, you can configure your importer to receive uploaded data in the onData
callback option.
type onDataResponseWithoutBatching = Promise<{
errors?: { row: Record<string, string | number | undefined>; error: string }[];
successes?: Record<string, string | number | undefined>[];
} | void>;
type onDataResponseWithBatching = Promise<{
errors?: { row: number; error: string }[];
successes?: Record<string, string | number | undefined>[];
} | void>;
onData?: (data: {
uploadId: number;
fileName: string;
matchedColumnsMap?: Record<string, string | number>;
uploadedFileHeaders?: Array<string>;
rows: Record<string, string | number>[];
user?: Record<string, string | number>;
metadata?: Record<string, string | number>;
importedRowsCount: number;
batch?: {
index: number;
count: number;
totalRows: number;
};
}, closeImporter: () => void) => void | onDataResponseWithoutBatching | onDataResponseWithBatching;
// usage example
var importButton = document.getElementById("import-data-button");
importButton.onclick = function () {
useCsvPlugin({
importerKey: "your-importer-key",
user: {
userId: "12345",
},
metadata: {
anotherId: "1",
},
onData: (data) => {
console.log(data);
},
});
};
// console output
{
uploadId: 334,
fileName: "data.csv",
user: { userId: "12345" },
metadata: { anotherId: "1" },
rows: [
{
row: 1, // row number
firstName: "Mari",
email: "mari@gmail.com",
},
{
row: 2, // row number
firstName: "John",
email: "john@gmail.com",
},
],
matchedColumnsMap: {
firstName: "first name",
email: "email address"
},
uploadedFileHeaders: ["first name", "email address", "age"]
};
onData
callback function parameters
data
: a first parameter json object:uploadId
: upload ID.fileName
: uploaded file name.user
json object of user object if provided.metadata
json object of metadata object if provided.matchedColumnsMap
: json object of matched columns with keys of configured columns and column names in the original user uploaded file.uploadedFileHeaders
: array of strings of uploaded file headers (column names) including matched, un-matched and skipped headers.rows
: array of json objects of rows, with keys of:row
: number of row in the uploaded file starting from 1.columnName
: cell value.
importedRowsCount
: total number of imported rows.batch
: json object of batch details sent only when using the batchSize option, with keys of:index
: number of batch starting from 1.count
: number of total batches expected to be received.totalRows
: number of total rows per file.
closeImporter
: a second parameter function that allows you to automatically close the importer modal.
Return successfully imported rows array
- Sometimes you might need to provide your users with new columns containing extra info after their data is imported successfully (for example a column of ids that are generated in your database), you can retrun an array of rows with any number of columns that user will be provided with a downloadable .csv file from the
Download .csv with imported rows
button in the final step.
Usage example
- Assume having an importer with only two configured columns: firstName and lastName, and you need to provide your user with an autogenerated id for each successfully importered row.
// usage example
var importButton = document.getElementById("import-data-button");
importButton.onclick = function () {
useCsvPlugin({
importerKey: "your-importer-key",
onData: async (data) => {
/*
* run your logic
*/
return Promise.resolve({
errors: [...],
successes: data.rows.map((row) => {
return {
...row,
newGeneratedId: getRandomId(), // newGeneratedId is a new column that is not configured in the importer
};
}),
});
},
});
};
Return errors
- You can retrun an array of rows with errors and the user will be provided with a downloadable .csv file containing the rejected rows and error messages.
Example of onData error handling without using batching (batchSize option is not passed to UseCSV)
var importButton = document.getElementById("import-data-button");
importButton.onclick = function () {
useCsvPlugin({
importerKey: "your-importer-key",
onData: async (data) => {
/*
* run your validation
*/
// if no errors
return;
// if you found rows with errors, save the correct rows, and retrun an array of rows with errors
return Promise.resolve({
errors: [
{
row: {
firstName: "Mari",
email: "mari@gmail.com",
},
error: "email already exists",
},
],
});
},
});
};
Example of onData error handling when using batching (batchSize option is passed to UseCSV)
Please note that using batchSize option requires the row number in onData callback errors response
var importButton = document.getElementById("import-data-button");
importButton.onclick = function () {
useCsvPlugin({
importerKey: "your-importer-key",
batchSize: 100,
onData: async (data) => {
/*
* run your validation
*/
// if no errors
return;
// if you found rows with errors, save the correct rows, and retrun an array of rows with errors
return Promise.resolve({
errors: [
{
row: 1, // must be the row number
error: "email already exists",
},
],
});
},
});
};
Validation Hooks
Validation Hooks allow you to validate user uploads during the interactive import process, so that your users can address any invalid data before it's imported into your app. When configuring your importer in the UseCSV admin, you can choose which columns to enable Validation Hooks for.
To use Validation Hooks you'll need to implement two callbacks: onRecordsInitial
and onRecordEdit
. They will pass you the uploaded data (for the columns Validation Hooks is enabled for) and allow you to return errors, info messages or heal values to the user.
Check using Validation Hooks codesandbox example
Check examples of using Data Healing:
- How to merge 2 or more columns codesandbox example
- How to split a column into 2 or more columns codesandbox example
- How to generate a unique id for a column codesandbox example
onRecordsInitial: Function
onRecordsInitial
callback function is triggered after the user uploads a file and once the column matching is completed. Data from the columns with Validation Hook
enabled will be sent to your frontend, so you can run your own validation and replace current value (Data Healing) or return rows with errors if any and custom error and info messages to be shown to the user. Data will be sent in batches of 1,000 rows by default if batchSize is not used.
type onRecordsInitial = ({
uploadId,
fileName,
importerId,
batch,
user,
metadata,
rows,
}: {
uploadId: string;
fileName: string;
importerId: string;
batch: {
index: number;
count: number;
totalRows: number;
};
user?: Record<string, string | number> | null;
metadata?: Record<string, string | number> | null;
rows: Array<{
row: number;
data: {
[columnName: string]: {
value: string | number | null;
isValid: boolean;
};
};
}>;
}) =>
| Promise<Array<{
row: number;
[columnName: string]: Array<{
message: string;
level: "error" | "info" | "healing";
newValue?: string; // required for healing level
}>;
}> | void>
| Array<{
row: number;
data: {
[columnName: string]: Array<{
message: string;
level: "error" | "info" | "healing";
newValue?: string; // required for healing level
}>;
};
}>
| void;
Usage example
Assuming Validation Hooks
are enabled for email
and age
columns only, where:
email
column is configured with validation format of email in admin panel.age
column is configured with validation format of number in admin panel
var importButton = document.getElementById("import-data-button");
importButton.onclick = function () {
useCsvPlugin({
importerKey: "your-importer-key",
user: {
userId: "12345",
},
metadata: {
anotherId: "1",
},
onRecordsInitial: ({
uploadId,
fileName,
importerId,
batch,
user,
metadata,
rows,
}) => {
console.log({
uploadId,
fileName,
importerId,
batch,
user,
metadata,
rows,
}); // check below the console output
// run custom validation
// if no errors
return;
// or return an array of errors
return [
{
row: 1,
data: {
email: [
{
message: "Email already exists", // first error message
level: "error",
},
{
message: "Invalid email", // second error message (optional)
level: "error",
},
],
age: [
{
message: "Age must be 18 or above",
level: "info",
},
],
},
},
{
row: 2,
data: {
age: [
{
message: "Age must be a number",
level: "error",
},
],
},
},
{
row: 3,
data: {
email: [
{
message: "Typo has been corrected",
level: "healing",
newValue: "invalid@gmail.com", // (notice the original email was invalid@gmail@.com)
},
],
},
},
];
},
});
};
// console output
{
uploadId: 334,
fileName: "data.csv",
importerId: "123-456-789"
batch: {
index: 1;
count: 1;
totalRows: 3;
},
user: {
userId: "12345",
},
metadata: {
anotherId: "1",
},
rows: [{
row: 1,
data: {
email: {
value: "mari@gmail.com",
isValid: true
}
age: {
value: 5,
isValid: true
}
}
},
{
row: 2,
data: {
email: {
value: "john@gmail.com",
isValid: true
},
age: {
value: "not a number",
isValid: false
}
}
} {
row: 3,
data: {
email: {
value: "invalid@gmail@.com",
isValid: false
},
age: {
value: 35,
isValid: true
}
}
}
]
}
onRecordsInitial
callback function parameters
type ParamsType = {
uploadId: string;
fileName: string;
importerId: string;
batch: {
index: number;
count: number;
totalRows: number;
};
user?: Record<string, string | number> | null;
metadata?: Record<string, string | number> | null;
rows: Array<{
row: number;
data: {
[columnName: string]: {
value: string | number | null;
isValid: boolean;
};
};
}>;
};
uploadId
: upload ID.fileName
: uploaded file name.importerId
: importer key that can be found in the admin panel.batch
: json object of batch details, with keys of:index
: number of batch starting from 1.count
: number of total batches expected to be received.totalRows
: number of total rows per file.
user
json object of user object if provided.metadata
json object of metadata object if provided.rows
: array of json objects of rows, with keys of:row
: number of row in the uploaded file starting from 1.data
: json object of columns:columnName
: array of json objects of the configured columns, with keys of:value
: value of cell.isValid
: boolean validation result according to the validation format configured for each column in admin panel when the column was created.
Return errors, info messages or heal values
onRecordsInitial hook accepts a returned value of an array of objects.
type ResponseType = Array<{
row: number;
data: {
[columnName: string]: Array<{
message: string;
level: "error" | "info" | "healing";
newValue?: string; // required for healing level
}>;
};
}>;
row
: required row number already included in the recieved data.data
: json object of columns:columnName
: array of json objects with keys of:message
andlevel
. At lease one column should be included in the response.message
: custom error message shown to user.level
:error
|info
:error
is used to define error messages.info
is used to define info messages.healing
is used to overwrite user's data.
newValue
: required string for healing level to replace current value in a cell.
onRecordEdit: Function
onRecordEdit
callback function is triggered after any of the cells is edited in the Match Columns step. The edited row will be sent to your frontend, so you can run your own validation and replace current value (Data Healing) or return errors if any and custom error and info messages to be shown to the user.
type onRecordEdit = ({
uploadId,
fileName,
importerId,
user,
metadata,
row,
}: {
uploadId: string;
fileName: string;
importerId: string;
user?: Record<string, string | number> | null;
metadata?: Record<string, string | number> | null;
row: {
row: number;
data: {
[columnName: string]: {
value: string | number | null;
isValid: boolean;
}
}
};
}) =>
| Promise<{
row: number;
data:{
[columnName: string]: Array<{
message: string;
level: "error" | "info" | "healing";
newValue?: string; // required for healing level
}
};
}> | void>
| {
row: number;
data: {
[columnName: string]: Array<{
message: string;
level: "error" | "info" | "healing";
newValue?: string; // required for healing level
}>
};
}
| void;
Usage example
Assuming Validation Hooks
are enabled for email
and age
columns only, where:
email
column is configured with validation format of email in admin panel.age
column is configured with validation format of number in admin panel
var importButton = document.getElementById("import-data-button");
importButton.onclick = function () {
useCsvPlugin({
importerKey: "your-importer-key",
user: {
userId: "12345",
},
metadata: {
anotherId: "1",
},
onRecordEdit: ({ uploadId, fileName, importerId, user, metadata, row }) => {
console.log({
uploadId,
fileName,
importerId,
user,
metadata,
row,
}); // check below the console output
// run custom validation
// if no errors
return;
// or return a json object
return Promise.resolve({
row: 2,
data: {
email: [
{
message: "Invalid email", // first error message
level: "error",
},
{
message: "Email does not exist", // second error message (optional)
level: "error",
},
{
message: "invalid@email.com", // optional suggestion (notice below in console output the original email was invalid@gmail@.com)
level: "info",
},
],
},
});
},
});
};
// console output
{
uploadId: 334,
fileName: "data.csv",
importerId: "123-456-789"
user: {
userId: "12345",
},
metadata: {
anotherId: "1",
},
row: {
row: 2,
data: {
email: {
value: "invalid@gmail@.com",
isValid: false
},
age: {
value: 35,
isValid: true
}
}
}
}
onRecordEdit
callback function parameters
type ParamsType = {
uploadId: string;
fileName: string;
importerId: string;
user?: Record<string, string | number> | null;
metadata?: Record<string, string | number> | null;
row: {
row: number;
data: {
[columnName: string]: {
value: string | number | null;
isValid: boolean;
};
};
};
};
uploadId
: upload ID.fileName
: uploaded file name.importerId
: importer key that can be found in the admin panel.user
json object of user object if provided.metadata
json object of metadata object if provided.row
: json object of edited row, with keys of:row
: number of row in the uploaded file.data
: json object of columns:columnName
: array of json objects of the configured columns, with keys of:value
: value of cell.isValid
: boolean validation result according to the validation format configured for each column in admin panel when the column was created.
Return errors, info messages or heal values
onRecordEdit hook accepts a returned value of a JSON object or an array of objects.
// JSON object or array of objects
type ResponseType =
| {
row: number;
data: {
[columnName: string]: Array<{
message: string;
level: "error" | "info" | "healing";
newValue?: string | number | null;
}>;
};
}
| Array<{
row: number;
data: {
[columnName: string]: Array<{
message: string;
level: "error" | "info" | "healing";
newValue?: string | number | null;
}>;
};
}>;
row
: required row number already included in the recieved data.data
: json object of columns:columnName
: json object with keys of:message
andlevel
. At lease one column should be included in the response.message
: custom error message shown to user.level
:error
|info
:error
is used to define error messages.info
is used to define info messages.healing
is used to overwrite user's data.
newValue
: required string for healing level to replace current value in a cell.