A flexible React component for mapping CSV columns to predefined fields with validation
npm install react-csv-mapper

A powerful, production-ready React CSV import component with intelligent column mapping, real-time validation, and a beautiful, themeable UI.
Seamlessly handle large CSV files with web worker-based parsing and built-in pagination
Quick import workflow for smaller CSV files (no pagination needed)
componentuseCsvMapper() hook for custom implementations``bash`
npm install react-csv-mapper
`tsx
import { CsvMapper } from 'react-csv-mapper';
function App() {
return (
{ key: 'name', label: 'Full 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);
}}
theme="indigo" // Optional: Choose from 18 themes or use hex color
/>
);
}
`
`tsx`
onSubmit={(data) => console.log(data)}
theme="emerald" // Named theme
// OR
theme="#0066ff" // Custom hex color
/>
`tsx`
onSubmit={(data) => console.log(data)}
theme="blue"
trigger={
}
/>
The component supports 18 built-in color themes with TypeScript autocomplete:
`tsx
type ThemeColor =
| 'blue' | 'indigo' | 'purple' | 'pink'
| 'red' | 'orange' | 'amber' | 'yellow'
| 'lime' | 'green' | 'emerald' | 'teal'
| 'cyan' | 'sky' | 'slate' | 'gray'
| 'zinc' | 'neutral' | 'stone';
`
Or use any custom hex color:
`tsx`
The theme automatically applies to:
- Primary buttons (Next, Submit)
- Links and interactive text
- Selected header rows
- Radio buttons and checkboxes
- Progress bars
- Borders on focus
- Active pagination buttons
The component comes with built-in dark mode support. You can control it in three ways:
1. Host Theme Detection: By default, it automatically detects if your website is in dark mode by checking for a .dark class or data-theme="dark" attribute. If it detects explicit "light" signals (like data-theme="default" or data-theme="light"), it strictly follows them.isDark
2. Safety Fallback: If no theme markers are found, it now defaults to Light Mode to maintain visual consistency with the majority of host websites, ignoring the system dark mode unless you explicitly enable it.
3. Manual Control: Use the prop to force a specific theme regardless of the site settings.
`tsx`
onSubmit={handleSubmit}
isDark={true} // Force dark mode even in a light theme environment
theme="indigo"
/>
When in dark mode, you can still use the theme prop to control the primary accent color.
| Prop | Type | Required | Description |
| ----------- | ------------------------------------------ | -------- | ----------------------------------------------------------- |
| columns | CsvColumn[] | ✅ Yes | Array of column definitions |onSubmit
| | (data: Record | ✅ Yes | Callback when data is submitted |theme
| | ThemeColor \| string | ❌ No | Theme color (named or hex) |trigger
| | React.ReactElement | ❌ No | Custom trigger button |container
| | string | ❌ No | Container selector (default: 'body') |isDark
| | boolean | ❌ No | Enable dark mode (Auto-detects site/system if not provided) |
`typescript`
interface CsvColumn {
key: string; // Unique identifier
label: string; // Display label
required?: boolean; // Is required?
default?: boolean; // Is selected by default?
validate?: (value: string) => true | string; // Custom validation
}
`tsx
import { useCsvMapper } from 'react-csv-mapper';
const { init, destroy } = useCsvMapper({
columns: [...],
onSubmit: (data) => console.log(data)
});
// Open mapper
`
`tsx`
{
key: 'email',
label: 'Email Address',
required: 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';
}
}
]}
onSubmit={async (data) => {
await fetch('/api/import', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data)
});
}}
theme="purple"
/>
`tsx
// 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
onSubmit={(data) => console.log(data)}
theme="teal"
/>
`
`tsx
import { CsvMapper, CsvColumn, ThemeColor } from 'react-csv-mapper';
interface UserData {
name: string;
email: string;
phone: string;
}
const columns: CsvColumn[] = [
{ key: 'name', label: 'Full Name', required: true, default: true },
{ key: 'email', label: 'Email', required: true, default: true },
{ key: 'phone', label: 'Phone Number' }
];
const theme: ThemeColor = 'indigo';
function ImportUsers() {
const handleSubmit = (data: Record
const users: UserData[] = data.map(row => ({
name: row.name,
email: row.email,
phone: row.phone || ''
}));
console.log(users);
};
return
}
``
1. Upload - Drag & drop 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
4. Validate & Edit - Review data, fix errors, add/remove rows (paginated view)
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.
MIT © Ahmad Nadeem
Contributions, issues and feature requests are welcome!
Give a ⭐️ if this project helped you!