CRM pipeline
Contacts table plus a five-stage deal pipeline board with inline stage changes, all persisted locally.
A small CRM with two views over the same data: a searchable contacts table with stage selects and delete, and a kanban-style pipeline (Lead → Qualified → Proposal → Won/Lost) where deals move between columns with keyboard-accessible buttons. State lives in localStorage via a typed hook so the app works offline; swap src/store.ts for API calls when you add a backend.
- react
- crm
- pipeline
- kanban
- tailwind
This preview is the template's actual file tree and source code — exactly what is copied into a new project. Codexa does not publish screenshots or mock-ups of templates; run the project to see it rendered.
Files14 files
import { useState } from "react";
import { STAGES, type Stage, type useContacts } from "./store";
export function ContactsTable({ store }: { store: ReturnType<typeof useContacts> }) {
const [q, setQ] = useState("");
const rows = store.contacts.filter((c) => [c.name, c.company, c.email].some((s) => s.toLowerCase().includes(q.toLowerCase())));
return (
<div className="rounded-xl border border-slate-200 bg-white">
<div className="flex flex-wrap items-center justify-between gap-3 border-b border-slate-200 p-3">
<input value={q} onChange={(e) => setQ(e.target.value)} placeholder="Search contacts" aria-label="Search contacts" className="rounded-md border border-slate-300 px-3 py-1.5 text-sm" />
<button type="button" onClick={store.reset} className="text-xs text-slate-500 hover:text-slate-900">
Reset sample data
</button>
</div>
<div className="overflow-x-auto">
<table className="w-full min-w-[640px] text-sm">
<thead className="text-left text-slate-500">
<tr>
<th className="p-3">Name</th>
<th className="p-3">Company</th>
<th className="p-3">Email</th>
<th className="p-3">Stage</th>
<th className="p-3">Value</th>
<th className="p-3">
<span className="sr-only">Actions</span>
</th>
</tr>
</thead>
<tbody>
{rows.map((c) => (
<tr key={c.id} className="border-t border-slate-100">
<td className="p-3 font-medium">{c.name}</td>
<td className="p-3">{c.company}</td>
<td className="p-3 text-slate-600">{c.email}</td>
<td className="p-3">
<select value={c.stage} onChange={(e) => store.update(c.id, { stage: e.target.value as Stage })} aria-label={"Stage for " + c.name} className="rounded border border-slate-300 px-2 py-1">
{STAGES.map((s) => (
<option key={s}>{s}</option>
))}
</select>
</td>
<td className="p-3">{"$" + c.value.toLocaleString()}</td>
<td className="p-3 text-right">
<button type="button" onClick={() => store.remove(c.id)} className="text-xs text-red-600 hover:underline">
Delete
</button>
</td>
</tr>
))}
{rows.length === 0 ? (
<tr>
<td colSpan={6} className="p-6 text-center text-slate-500">
No contacts found.
</td>
</tr>
) : null}
</tbody>
</table>
</div>
</div>
);
}
Dependencies
Documented from the template's package.json. The runtime has a prebuilt dependency set for Vite + React + TypeScript, so installs are fast.
| Package | Version |
|---|---|
| react | ^19.1.0 |
| react-dom | ^19.1.0 |
| vite | ^6.3.0 |
| @vitejs/plugin-react | ^4.4.0 |
| tailwindcss | ^4.1.0 |
| @tailwindcss/vite | ^4.1.0 |
| typescript | ^5.8.0 |
How it runs
- Framework
- Vite + React + TypeScript
- Dev command
- npm run dev
- Build command
- npm run build
- Output directory
- dist
- Port
- 5173
- Opens at
- /
- Difficulty
- intermediate
Projects run in an isolated sandbox with a live preview. Read the projects documentation for details on settings, snapshots and deployment.
Need the raw data? GET /api/v1/templates/vite-react-crm returns this template with its files.
Build on CRM pipeline
Create a free account, start from this template, and ask the AI agent to turn it into your app.