A powerful, production-ready vanilla JavaScript CSV import library with intelligent column mapping, real-time validation, and a beautiful, themeable UI
npm install csv-column-mapper

A powerful, production-ready vanilla JavaScript CSV import library with intelligent column mapping, real-time validation, and a beautiful, themeable UI. Perfect for building data import features without any framework dependencies.
Seamlessly handle large CSV files with web worker-based parsing and built-in pagination
Quick import workflow for smaller CSV files (no pagination needed)
Seamlessly handle large CSV files with web worker-based parsing and built-in pagination
``bash`
npm install csv-column-mapper
`html
`
`javascript
import CsvMapper from 'csv-column-mapper';
const mapper = new CsvMapper('body', {
columns: [
{ key: 'firstName', label: 'First Name', required: true, default: true },
{ key: 'lastName', label: 'Last Name', required: true, default: true },
{ key: 'email', label: 'Email', required: true, default: true },
{ key: 'phone', label: 'Phone Number' }
],
onSubmit: (data) => {
console.log('Imported data:', data);
}
});
// Trigger from your button
document.querySelector('#import-btn').addEventListener('click', () => {
mapper.init();
});
`
The library uses an indigo theme by default. You can customize it by overriding CSS variables:
`html`
`css`
:root {
--csv-primary: #6366f1; / Main theme color /
--csv-primary-hover: #4f46e5; / Hover state /
--csv-primary-light: #eef2ff; / Light backgrounds /
--csv-primary-dark: #4338ca; / Dark text on light bg /
--csv-bg-main: #f9fafb; / Main background /
--csv-bg-card: #ffffff; / Card backgrounds /
--csv-text-primary: #111827; / Primary text /
--csv-text-secondary: #6b7280; / Secondary text /
--csv-border: #e5e7eb; / Borders /
--csv-border-dark: #d1d5db; / Darker borders /
}
`javascript`
new CsvMapper(selector, options)
Parameters:
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| selector | string | ✅ Yes | CSS selector for container (e.g., 'body', '#app') |options
| | object | ✅ Yes | Configuration options |
Options:
| Option | Type | Required | Description |
|--------|------|----------|-------------|
| columns | array | ✅ Yes | Array of field definitions |onSubmit
| | function | ✅ Yes | Callback when data is submitted |
`javascript`
{
key: 'fieldName', // Unique identifier (required)
label: 'Display Name', // User-facing label (required)
required: true, // Is field required? (optional)
default: true, // Show by default? (optional)
validate: (value) => {} // Custom validation (optional)
}
Return true if valid, or an error message string if invalid:
`javascript
validate: (value) => {
if (!value) return true; // Allow empty if not required
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!emailRegex.test(value)) {
return 'Invalid email format';
}
return true;
}
`
#### init()
Opens the CSV mapper modal.
`javascript`
mapper.init();
#### destroy()
Closes and cleans up the mapper.
`javascript`
mapper.destroy();
`javascript`
const mapper = new CsvMapper('body', {
columns: [
{
key: 'email',
label: 'Email Address',
required: true,
default: true,
validate: (value) => {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailRegex.test(value) ? true : 'Invalid email format';
}
},
{
key: 'age',
label: 'Age',
validate: (value) => {
if (!value) return true;
const age = parseInt(value);
return (age >= 0 && age <= 120) ? true : 'Age must be 0-120';
}
},
{
key: 'phone',
label: 'Phone Number',
validate: (value) => {
if (!value) return true;
const phoneRegex = /^\+?[\d\s-()]+$/;
return phoneRegex.test(value) ? true : 'Invalid phone format';
}
}
],
onSubmit: async (data) => {
await fetch('/api/import', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data)
});
}
});
`javascript
// Define all possible fields
const allFields = [
{ key: 'firstName', label: 'First Name', default: true },
{ key: 'lastName', label: 'Last Name', default: true },
{ key: 'email', label: 'Email', required: true, default: true },
{ key: 'phone', label: 'Phone' },
{ key: 'company', label: 'Company' },
{ key: 'title', label: 'Job Title' },
{ key: 'address', label: 'Address' },
{ key: 'city', label: 'City' },
{ key: 'country', label: 'Country' }
];
// Users can select which fields to import via the UI
const mapper = new CsvMapper('body', {
columns: allFields,
onSubmit: (data) => console.log(data)
});
`
`html
`
1. Upload - Drag & drop, file upload, or paste CSV data
2. Select Header - Choose which row contains column headers (with pagination for large files)
3. Map Columns - Auto-mapped or manually map CSV columns to your fields
- Add/remove optional fields dynamically
- See all available fields in dropdown
4. Validate & Edit - Review data, fix errors, add/remove rows (paginated view)
- Inline editing with real-time validation
- Filter to show only errors
- Automatic duplicate detection
5. Submit - Clean, validated data ready for your API
- ✅ Chrome (latest)
- ✅ Firefox (latest)
- ✅ Safari (latest)
- ✅ Edge (latest)
Requires Web Worker support for large file processing.
Looking for a React component? Check out react-csv-mapper` - a React wrapper with the same features plus:
- React component & hook APIs
- 18 built-in theme colors
- TypeScript support out of the box
MIT © Ahmad Nadeem
Contributions, issues and feature requests are welcome!
Feel free to check the issues page.
Give a ⭐️ if this project helped you!