Papa Parse CSV Import Validator with Error Report — Free JavaScript Snippet

Papa Parse CSV Import Validator with Error Report · Tools · Plain HTML, CSS & JS · Live preview

What's included

Features

Robust CSV parsing
Quotes, commas and line breaks in fields.
Delimiter detection
Comma, semicolon or tab, reported in the stats.
Header normalisation
transformHeader maps variations to keys.
Per-column typing
dynamicTyping only where numbers are expected.
Schema validation
Required, email, enum, range and real-date rules.
Duplicate detection
Points to the original row.
Cell-level highlighting
Plus a line-numbered error list.
Clean export
Papa.unparse for valid rows only.

About this UI Snippet

CSV Import Validation With Papa Parse — Catch Bad Rows Before They Reach Your Database

Screenshot of the Papa Parse CSV Import Validator with Error Report snippet rendered live

Every "import from CSV" feature eventually receives a spreadsheet exported from somewhere else: headers with odd capitalisation, a missing column, emails with typos, values out of range, dates that can't exist. Validating in the browser gives users immediate, line-numbered feedback they can fix before anything is uploaded. Papa Parse handles the hard part — parsing CSV correctly — and this snippet adds a schema on top.

Parsing properly is not split(',')

Real CSV has quoted fields containing commas ("Johnson, Katherine"), escaped quotes and line breaks inside cells. Papa Parse handles all of these, detects the delimiter automatically, and reports structural problems such as a row with too few fields as errors with a code and row index.

Normalising headers

header: true returns each row as an object keyed by column name. transformHeader trims, lowercases and replaces spaces with underscores, so "Signup_Date", "signup date" and " SIGNUP_DATE" all map to the same key.

Typing only what should be typed

dynamicTyping converts numeric-looking strings to numbers. Enabling it globally is a classic bug: ZIP codes, phone numbers and IDs lose leading zeros. Passing an object — { seats: true } — types only the columns that are really numbers.

Schema rules

Each expected column has a function returning an error or null: required fields, an email pattern, an allowed set of plans, a 1–500 whole-number range, and a date check that round-trips through Date.UTC so "2026-13-40" is rejected even though it matches the pattern. The first occurrence of each email is remembered so duplicates point back to the original line.

Reporting in the user's line numbers

Errors use spreadsheet-style line numbers (data index + 2, accounting for the header), and the preview highlights exactly which cells failed.

Exporting clean rows

Papa.unparse turns the valid rows back into correctly quoted CSV for download.

Build with AI

Build, Understand, Optimize, and Extend It With AI

Paste this snippet into an AI assistant like Claude and ask it to add a rule for a new column, or to explain why dynamicTyping is restricted. Ask it to add inline editing of bad cells in the preview table, a column-mapping step for files with different headers, streaming large files with Papa's step callback, or sending the valid rows to an API in batches.

Prompt to recreate it

Copy this into your AI assistant of choice to build the effect from scratch, or as a jumping-off point for your own variant:

text
Build a CSV import validator with Papa Parse (from a CDN) in plain HTML, CSS and JavaScript.

Requirements:
- A textarea preloaded with a sample customer CSV containing typical problems (invalid email, missing name, unknown plan, out-of-range seats, duplicate email, impossible date, a quoted field containing a comma, a row with too few fields), and a file chooser that reads a CSV with Papa.
- Parse with header rows, greedy empty-line skipping, headers normalised to lowercase underscore keys, and numeric typing only for the seats column.
- Validate each row against a schema: required email with a valid format and no duplicates (pointing to the first occurrence), required name, plan in free/pro/team, seats as a whole number 1–500, and signup_date as YYYY-MM-DD that is a real calendar date; also report missing columns and Papa's structural errors.
- Show stats (rows, valid, problems, detected delimiter), a preview table with spreadsheet line numbers and invalid cells highlighted, and a list of errors with line numbers and column names.
- Re-validate as the user edits, escape all displayed values, and offer a download of only the valid rows using Papa.unparse.

Want to tighten it up first? Run this prompt through the AI Prompt Studio to score it across 8 quality dimensions, catch anti-patterns, and tune the wording for Claude, ChatGPT, or Gemini before you paste it in.

Source Code

Requires
<div class="pp">
  <header class="pp-head">
    <div>
      <h2>Import customers from CSV</h2>
      <p>Expected columns: <code>email</code>, <code>name</code>, <code>plan</code> (free / pro / team), <code>seats</code> (1–500), <code>signup_date</code> (YYYY-MM-DD).</p>
    </div>
    <label class="pp-file">Choose CSV<input type="file" id="ppFile" accept=".csv,text/csv"></label>
  </header>
  <div class="pp-grid">
    <div class="pp-input">
      <label for="ppText" class="pp-label">Paste CSV (or edit the sample)</label>
      <textarea id="ppText" spellcheck="false"></textarea>
    </div>
    <div class="pp-out">
      <div class="pp-stats" id="ppStats" aria-live="polite"></div>
      <div class="pp-tablewrap"><table class="pp-table" id="ppTable"></table></div>
      <ul class="pp-errors" id="ppErrors"></ul>
      <div class="pp-actions">
        <button type="button" id="ppClean">Download valid rows (CSV)</button>
        <span id="ppStatus" role="status"></span>
      </div>
    </div>
  </div>
</div>

Step by step

How to Use

  1. 1
    Review the sampleTen rows with typical problems are validated on load.
  2. 2
    Read the reportEach problem cites its line number and column; bad cells are red.
  3. 3
    Fix the textEdit the CSV and the validation reruns as you type.
  4. 4
    Load your own fileChoose a CSV; Papa reads and decodes it locally.
  5. 5
    Export clean rowsDownload only the rows that passed every rule.

Real-world uses

Common Use Cases

SaaS onboarding
Bulk-import users, contacts or products.
CRM and email tools
Validate contact lists before sending.
E-commerce
Catalogue and inventory uploads.
Admin panels
Safer bulk edits with a preview.
Data cleaning
Quickly filter the usable rows.
Related: CSV Import Mapper
Map arbitrary columns first: CSV Import Mapper.
Related: SheetJS Excel Export and Import

Got questions?

Frequently Asked Questions

Use Papa Parse: Papa.parse(fileOrString, { header: true, complete: fn }). It handles quoted fields, embedded commas and line breaks, detects the delimiter and can read File objects directly.

It converts anything that looks numeric into a number, which strips leading zeros from ZIP codes, phone numbers and IDs. Pass an object listing only the numeric columns instead.

Papa's data index starts at 0 for the first data row. Add 1 for the header row and 1 more to make it 1-based: line = index + 2.

After checking the format, build a date with Date.UTC(year, month − 1, day) and confirm the resulting month and day are the ones you passed in. JavaScript rolls invalid dates over, so a mismatch means the date doesn't exist.

Papa.unparse(arrayOfObjects) produces CSV with a header row and correctly quotes values containing commas, quotes or line breaks.