# Data import mapping

> A light import wizard: columns from a CSV are matched to our fields with drawn connector lines, then Import is pressed.

- Category: Developer tools
- Version: 1.0
- Source: https://ownlyplans.com/bhaskar/data-import-mapping/

## Overview

Two cards face each other, your file columns on the left and the product fields on the right. Blue lines draw between matching columns, matched fields turn green, a confirmation shows 248 contacts ready and the Import button is pressed. Topic inspired by OpenDesign's public dashboard prompt list; this prompt and design are written from scratch.

## Tech stack

- CSS
- Dashboard
- HTML

## Build steps

### 1. Paste the prompt

The AI builds both cards and the connector lines.

Prompt:

```text
Create a single-file HTML data import mapping screen, 1280x720, pale slate background #f1f5f9, ink #0f172a, accent blue #2563eb, success green #16a34a. System fonts, no libraries.
Header: title "Import contacts" and subtitle "Match the columns from your CSV to our fields".
Left white card "Your file - contacts.csv" with five field boxes (60px tall, 1.5px border, 14px radius): Full Name, E-mail Address, Company / Org, Phone #, Notes, each with a muted sample line. Right white card "Our fields" with Name (required), Company (optional), Email (required - used to dedupe), Phone (optional - skipped).
Between the cards place an inline SVG with three connector paths (Full Name to Name, E-mail Address to Email, Company / Org to Company), drawn with stroke-dasharray and animated with stroke-dashoffset one after another (blue, 3px, round caps, the paths can cross).
Motion (8 second loop): boxes rise in; each connector draws and, when it reaches its target, the target box turns green (border and tint). Then a green confirmation chip "3 columns matched - 248 contacts ready" slides up bottom left, and the blue "Import 248 contacts" button bottom right presses (scale .92). Reset at the end.
Respect prefers-reduced-motion. Return only the complete HTML.
```

### 2. Check the lines

Three lines should draw one after another.

### 3. Check the matches

Matched fields should turn green and the chip should appear.

**Done when:** You can see it working in the browser.

### 4. Make it real

Let people drag a column onto a field and save the mapping.

## Assets

### prompt.md — The full prompt.

~~~~
# Data import mapping

Copy this prompt into Claude, Cursor or Lovable.

```text
Create a single-file HTML data import mapping screen, 1280x720, pale slate background #f1f5f9, ink #0f172a, accent blue #2563eb, success green #16a34a. System fonts, no libraries.
Header: title "Import contacts" and subtitle "Match the columns from your CSV to our fields".
Left white card "Your file - contacts.csv" with five field boxes (60px tall, 1.5px border, 14px radius): Full Name, E-mail Address, Company / Org, Phone #, Notes, each with a muted sample line. Right white card "Our fields" with Name (required), Company (optional), Email (required - used to dedupe), Phone (optional - skipped).
Between the cards place an inline SVG with three connector paths (Full Name to Name, E-mail Address to Email, Company / Org to Company), drawn with stroke-dasharray and animated with stroke-dashoffset one after another (blue, 3px, round caps, the paths can cross).
Motion (8 second loop): boxes rise in; each connector draws and, when it reaches its target, the target box turns green (border and tint). Then a green confirmation chip "3 columns matched - 248 contacts ready" slides up bottom left, and the blue "Import 248 contacts" button bottom right presses (scale .92). Reset at the end.
Respect prefers-reduced-motion. Return only the complete HTML.
```
~~~~

### index.html.md — Complete code of the result in the video.

~~~~
# index.html

The finished result as one file. Save it as index.html and open it.

```html
<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Data import mapping</title><style>*{box-sizing:border-box;margin:0;padding:0}
html,body{width:1280px;height:720px;overflow:hidden}
body{font-family:ui-sans-serif,system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;-webkit-font-smoothing:antialiased}
@property --n{syntax:'<integer>';inherits:false;initial-value:0}
.stage{position:absolute;inset:0;animation:cyc 8s linear infinite both}
@keyframes cyc{0%{opacity:0}4%{opacity:1}94%{opacity:1}100%{opacity:0}}
body:not(.go) *,body:not(.go) *::before,body:not(.go) *::after{animation-play-state:paused!important}
.cnt::after{content:counter(n)}.cnt{counter-reset:n var(--n)}
@media (prefers-reduced-motion:reduce){*{animation:none!important}}


body{background:#f1f5f9;color:#0f172a}
.t{position:absolute;left:48px;top:30px;font-size:28px;font-weight:800;letter-spacing:-.03em}.sb{position:absolute;left:48px;top:72px;font-size:14px;color:#64748b}
.p{position:absolute;top:120px;height:540px;background:#fff;border-radius:22px;padding:24px;box-shadow:0 18px 40px -30px #0f172a}
.l{left:48px;width:430px}.r{right:48px;width:430px}
.p h2{font-size:12px;letter-spacing:.1em;text-transform:uppercase;color:#64748b;margin-bottom:16px}
.f{position:absolute;left:24px;right:24px;height:60px;border:1.5px solid #d9e2ec;border-radius:14px;padding:11px 16px;font-size:15px;background:#fff}.f small{display:block;color:#64748b;font-size:12px;margin-top:2px;white-space:nowrap;overflow:hidden}
.l .f{animation:fi 8s infinite both}.r .f{animation:fi 8s infinite both}
@keyframes fi{0%,4%{opacity:0;transform:translateY(10px)}12%,100%{opacity:1;transform:none}}
.r .f.mt{animation:mt 8s infinite both}
@keyframes mt{0%,var(--x){border-color:#d9e2ec}}
.m1{animation:fi 8s infinite both,k1 8s infinite both!important}@keyframes k1{0%,26%{border-color:#d9e2ec;background:#fff}32%,100%{border-color:#16a34a;background:#f0fdf4}}
.m2{animation:fi 8s infinite both,k2 8s infinite both!important}@keyframes k2{0%,42%{border-color:#d9e2ec;background:#fff}48%,100%{border-color:#16a34a;background:#f0fdf4}}
.m3{animation:fi 8s infinite both,k3 8s infinite both!important}@keyframes k3{0%,58%{border-color:#d9e2ec;background:#fff}64%,100%{border-color:#16a34a;background:#f0fdf4}}
svg{position:absolute;left:478px;top:120px;width:324px;height:540px}
.ln{fill:none;stroke:#2563eb;stroke-width:3;stroke-linecap:round;stroke-dasharray:340;stroke-dashoffset:340}
.d1{animation:d1 8s infinite both}.d2{animation:d2 8s infinite both}.d3{animation:d3 8s infinite both}
@keyframes d1{0%,16%{stroke-dashoffset:340}28%,100%{stroke-dashoffset:0}}@keyframes d2{0%,32%{stroke-dashoffset:340}44%,100%{stroke-dashoffset:0}}@keyframes d3{0%,48%{stroke-dashoffset:340}60%,100%{stroke-dashoffset:0}}
.bt{position:absolute;right:48px;bottom:36px;background:#2563eb;color:#fff;border-radius:14px;padding:15px 28px;font-weight:700;animation:bt 8s infinite both}
@keyframes bt{0%,70%{transform:none}74%{transform:scale(.92)}78%,100%{transform:none}}
.ok{position:absolute;left:48px;bottom:36px;background:#dcfce7;border:1px solid #16a34a;color:#166534;font-weight:700;border-radius:14px;padding:15px 22px;opacity:0;animation:ok 8s infinite both}
@keyframes ok{0%,78%{opacity:0;transform:translateY(12px)}84%,94%{opacity:1;transform:none}100%{opacity:0}}
</style></head><body><div class="stage"><div class="t">Import contacts</div><div class="sb">Match the columns from your CSV to our fields</div>
<div class="p l"><h2>Your file - contacts.csv</h2><div class="f" style="top:70px">Full Name<small>Dana Whitfield, Marco Bellini...</small></div><div class="f" style="top:150px">E-mail Address<small>dana@orbit.co, marco@tidal.io...</small></div><div class="f" style="top:230px">Company / Org<small>Orbit Retail, Tidal Foods...</small></div><div class="f" style="top:310px">Phone #<small>+1 555 0132, +39 06 5550...</small></div><div class="f" style="top:390px">Notes<small>Met at SaaStr, prefers email...</small></div></div>
<svg viewBox="0 0 324 540"><path class="ln d1" d="M0 100 C120 100 200 100 324 100"/><path class="ln d2" d="M0 180 C120 180 200 260 324 260"/><path class="ln d3" d="M0 260 C120 260 200 180 324 180"/></svg>
<div class="p r"><h2>Our fields</h2><div class="f m1" style="top:70px">Name<small>required</small></div><div class="f m3" style="top:150px">Company<small>optional</small></div><div class="f m2" style="top:230px">Email<small>required - used to dedupe</small></div><div class="f" style="top:310px">Phone<small>optional - skipped</small></div></div>
<div class="ok">3 columns matched - 248 contacts ready</div><div class="bt">Import 248 contacts</div></div><script>window.start=function(){document.body.classList.add("go")};if(!/[?&]rec/.test(location.search))start();</script></body></html>
```
~~~~


## Build instructions by tool

### Claude Code

Open a terminal in an empty folder, run `claude`, then paste the prompt.

```text
Build the "Data import mapping" app from the OwnlyPlans blueprint at https://ownlyplans.com/bhaskar/data-import-mapping/.
Stack: CSS, Dashboard, HTML.
Follow the plan's steps in order: Paste the prompt → Check the lines → Check the matches → Make it real.
Download the full plan (Markdown) from the link above and keep it in the project root as PLAN.md.
Ask me before adding anything not in the plan. (Prepared for Claude Code.)
```

### Cursor

Open an empty folder in Cursor, start an Agent chat, then paste the prompt.

```text
Build the "Data import mapping" app from the OwnlyPlans blueprint at https://ownlyplans.com/bhaskar/data-import-mapping/.
Stack: CSS, Dashboard, HTML.
Follow the plan's steps in order: Paste the prompt → Check the lines → Check the matches → Make it real.
Download the full plan (Markdown) from the link above and keep it in the project root as PLAN.md.
Ask me before adding anything not in the plan. (Prepared for Cursor.)
```

### Lovable

Start a new Lovable project and paste the prompt as your first message.

```text
Build the "Data import mapping" app from the OwnlyPlans blueprint at https://ownlyplans.com/bhaskar/data-import-mapping/.
Stack: CSS, Dashboard, HTML.
Follow the plan's steps in order: Paste the prompt → Check the lines → Check the matches → Make it real.
Download the full plan (Markdown) from the link above and keep it in the project root as PLAN.md.
Ask me before adding anything not in the plan. (Prepared for Lovable.)
```

## Definition of done

- Every build step is complete and the app runs locally.
- The main user flow works end to end.
- Share your build on OwnlyPlans with a demo link, build time and tool.
