Skip to main content

Options

Required

importerKey: string

Which 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";
}

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
});
};

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");
},
});
};

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 and position: 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",
});
}
Inline importer modal

theme: json object

You can edit each CSS property in the next UseCSV default theme object, and pass it to the theme option. The theme object should have the same exact keys as below.

{
"global": {
"backgroundColor": "#FFFFFF",
"primaryTextColor": "#3182CE",
"secondaryTextColor": "#A0AEC0",
"successColor": "#38A169",
"warningColor": "#C53030"
},
"buttons": {
"primary": {
"backgroundColor": "#3182CE",
"color": "#FFFFFF",
"border": "none",
"borderRadius": "0.375rem",
"boxShadow": "0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06)",
":hover": {
"backgroundColor": "#2f679c",
"color": "#FFFFFF"
}
},
"secondary": {
"backgroundColor": "#FFFFFF",
"color": "#214464",
"border": "1px solid #EDF2F7",
"borderRadius": "0.375rem",
"boxShadow": "0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06)",
":hover": {
"backgroundColor": "#F7FAFC",
"color": "#214464"
}
}
}
}
// usage example
var importButton = document.getElementById("import-data-button");
importButton.onclick = function () {
useCsvPlugin({
importerKey: "your-importer-key",
onClose: () => {
console.log("Importer modal is closed");
},
theme: {
global: {
backgroundColor: "#212327",
primaryTextColor: "#c2c3c3",
secondaryTextColor: "#ffffff",
successColor: "#c2c3c3",
warningColor: "#c2c3c3"
},
buttons: {
primary: {
backgroundColor: "#00D1AF",
color: "#002d3d",
border: "1px solid transparent",
borderRadius: "1px",
boxShadow: "0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06)",
:hover: {
backgroundColor: "#00D1AF",
color: "#002d3d"
}
},
secondary: {
backgroundColor: "#d9ccff",
border: "1px solid #ece6ff",
color: "#002d3d",
borderRadius: "1px",
boxShadow: "0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06)",
:hover: {
backgroundColor: "#794cff",
color: "#c2c3c3"
}
}
}
}
});
};

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 }[] } | void>;

type onDataResponseWithBatching = Promise<{ errors?: { row: number; error: string }[] } | void>;

onData?: (data: {
uploadId: number;
rows: Record<string, string | number | undefined>[];
metadata?: Record<string, string | number> | null;
user?: Record<string, string | number> | null;
}) => 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
first_name: "Mari",
email: "mari@gmail.com",
},
{
row: 2, // row number
first_name: "John",
email: "john@gmail.com",
},
],
};

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: {
first_name: "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 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:

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;
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
}
}
}
]
}
Data table with comments and errors
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;
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.
  • metadatajson 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
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 and level. 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;
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;
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.
  • metadatajson 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
type ResponseType = {
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: json object with keys of: message and level. 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.