Invoice Generator with PDF Download
Fill in client and line items, see a live preview, download a clean PDF. Totals in integer cents, saved in the browser, no backend.
Use it with Claude or any AI tool. Copy the prompt and paste it in. The link inside gives the AI the whole page as Markdown.
Overview
Every freelancer needs one and most invoice tools want a subscription. This plan builds a fast, private invoice generator: your data never leaves the browser, totals are calculated correctly (in cents, so no rounding surprises), and the PDF looks professional.
It is also a great small project for learning how to keep one source of truth that both the screen and a PDF use.
Before you start: Node.js 20+ and Claude Code, Cursor or Lovable. About 2 hours.
Build it step by step
Sign in to tick steps off-
1
Create the app
Run:
npx create-next-app@latest invoice --ts --tailwind --app
cd invoice
npm i @react-pdf/renderer zodSave CLAUDE.md in the project root.
Read CLAUDE.md and confirm the rules back to me in a short list. Then replace the home page with a two-column layout: a form on the left, a preview on the right (stacked on mobile). Placeholders only.
Done when The two-column layout shows at localhost:3000 and stacks on a phone-sized window.
Uses CLAUDE.md
-
2
One source of truth for the invoice
Get the data model and the maths right before any UI. Everything else reads from here.
Create lib/invoice.ts: an Invoice type and zod schema (number, issue and due dates, currency, from and to blocks with name/address/email, line items with description, quantity and unit price in cents, tax rate in percent, discount in cents, notes). Add calcTotals(invoice) returning subtotal, tax and total in integer cents (round tax half up once, at the end). Add unit tests for: no items, one item, tax 20%, discount larger than subtotal (total never below 0).
Done when All tests pass with node --test or vitest.
Uses CLAUDE.md
-
3
The form
Line items are the heart of it: add, remove, reorder. Prices are typed in normal currency but stored as cents.
Build the form with controlled inputs for every field. Line items: add row, remove row, move up/down, quantity accepts decimals like 1.5, price input converts to cents on blur. Show validation messages from the zod schema under each field. Auto-number new invoices as INV-0001, INV-0002 and so on.
Done when You can add three items, change quantities and see validation on an empty client name.
-
4
Live preview
The preview should look like the PDF so there are no surprises.
Render the invoice preview on the right from the same Invoice state: header with invoice number and dates, from/to blocks, an items table with right-aligned money columns, then subtotal, tax, discount and a bold total, then notes. Format money with Intl.NumberFormat and the chosen currency.
Done when Every change in the form appears in the preview immediately with correct totals.
-
5
PDF download
Use React-pdf to build the PDF from the same data and calcTotals(). Load it only on the client to keep the page fast.
Create components/InvoicePdf.tsx with @react-pdf/renderer that mirrors the preview layout on A4. Add a Download PDF button that loads the PDF code with a dynamic import (client only) and saves the file as INV-0001.pdf. Use the built-in Helvetica font.
Done when The downloaded PDF matches the preview and the totals are identical.
-
6
Save, reuse and duplicate
Freelancers send the same kind of invoice every month. Make the second one take ten seconds.
Save the "from" details and the current draft to localStorage automatically. Add a saved-invoices list (number, client, total, date) with Open, Duplicate (new number, today's date) and Delete with a confirm step. Add Export JSON and Import JSON for backups.
Done when Refreshing keeps your draft; Duplicate creates the next invoice number with the same items.
-
7
Final checks
Check the maths, the print view and mobile, then deploy it for free on Vercel.
Walk me through a final check: totals with 3 items, 7.5% tax and a discount; a very long client address; 25 line items (PDF must break onto a second page with the table header repeated); a 390px wide phone; keyboard-only use of the form. Fix anything that fails.
Done when All checks pass and the app is live on your Vercel URL.
Files and links
What people built
Show yoursNobody has shared a build yet. Yours could be the first.
Show what you built
Built this plan? Sign in to share your demo video, live app and screenshots.