Skip to content
Framework: Vite + React + TypeScriptDifficulty: intermediate

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

src/Pipeline.tsx42 lines
import { STAGES, type Stage, type useContacts } from "./store";

export function Pipeline({ store }: { store: ReturnType<typeof useContacts> }) {
  const move = (id: string, dir: -1 | 1, current: Stage) => {
    const i = STAGES.indexOf(current);
    const next = STAGES[i + dir];
    if (next) store.update(id, { stage: next });
  };
  return (
    <div className="grid gap-3 md:grid-cols-5">
      {STAGES.map((stage) => {
        const items = store.contacts.filter((c) => c.stage === stage);
        return (
          <section key={stage} aria-labelledby={"stage-" + stage} className="rounded-xl border border-slate-200 bg-white p-3">
            <h2 id={"stage-" + stage} className="flex items-center justify-between text-sm font-medium">
              {stage}
              <span className="rounded-full bg-slate-100 px-2 text-xs text-slate-600">{items.length}</span>
            </h2>
            <ul className="mt-3 space-y-2">
              {items.map((c) => (
                <li key={c.id} className="rounded-lg border border-slate-200 p-3 text-sm">
                  <p className="font-medium">{c.company}</p>
                  <p className="text-slate-600">{c.name}</p>
                  <p className="mt-1 text-xs text-slate-500">{"$" + c.value.toLocaleString()}</p>
                  <div className="mt-2 flex justify-between">
                    <button type="button" onClick={() => move(c.id, -1, c.stage)} disabled={stage === STAGES[0]} className="rounded border border-slate-300 px-2 py-0.5 text-xs disabled:opacity-40" aria-label={"Move " + c.company + " back"}>
                      ←
                    </button>
                    <button type="button" onClick={() => move(c.id, 1, c.stage)} disabled={stage === STAGES[STAGES.length - 1]} className="rounded border border-slate-300 px-2 py-0.5 text-xs disabled:opacity-40" aria-label={"Move " + c.company + " forward"}>
                      →
                    </button>
                  </div>
                </li>
              ))}
              {items.length === 0 ? <li className="rounded-lg border border-dashed border-slate-200 p-3 text-center text-xs text-slate-400">Empty</li> : null}
            </ul>
          </section>
        );
      })}
    </div>
  );
}

Dependencies

Documented from the template's package.json. The runtime has a prebuilt dependency set for Vite + React + TypeScript, so installs are fast.

PackageVersion
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.