<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Abdul Ahad</title>
    <description>The latest articles on DEV Community by Abdul Ahad (@ahadkhan2401).</description>
    <link>https://dev.to/ahadkhan2401</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4055581%2Fc4793bab-d739-4089-952b-18679add0086.png</url>
      <title>DEV Community: Abdul Ahad</title>
      <link>https://dev.to/ahadkhan2401</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ahadkhan2401"/>
    <language>en</language>
    <item>
      <title>I built a PDF invoice generator that never sends your data to a server</title>
      <dc:creator>Abdul Ahad</dc:creator>
      <pubDate>Thu, 30 Jul 2026 18:52:24 +0000</pubDate>
      <link>https://dev.to/ahadkhan2401/i-built-a-pdf-invoice-generator-that-never-sends-your-data-to-a-server-4l4d</link>
      <guid>https://dev.to/ahadkhan2401/i-built-a-pdf-invoice-generator-that-never-sends-your-data-to-a-server-4l4d</guid>
      <description>&lt;p&gt;Most online invoice tools upload your data. Your client names, your rates, what you earn — it all sits on someone's server. For a tool whose entire job is producing one PDF, that always felt like a bad trade.&lt;/p&gt;

&lt;p&gt;So I built &lt;a href="https://www.pdfbillbuilder.com" rel="noopener noreferrer"&gt;PDF Bill Builder&lt;/a&gt; with a hard rule: nothing leaves the browser.&lt;/p&gt;

&lt;h2&gt;
  
  
  The stack
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Next.js 16&lt;/strong&gt; (App Router) + &lt;strong&gt;React 19&lt;/strong&gt; + TypeScript&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;jsPDF + html2canvas&lt;/strong&gt; for PDF generation — both dynamically imported, so they only load when someone actually clicks Download&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tailwind CSS v4&lt;/strong&gt; for the marketing pages; the tool itself uses inline styles (deliberate — see below)&lt;/li&gt;
&lt;li&gt;Optional tier: Neon Postgres + Google OAuth + HMAC-signed tokens&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why the tool uses inline styles
&lt;/h2&gt;

&lt;p&gt;The PDF is rendered by rasterising the live preview DOM with html2canvas. Any style that isn't computed at capture time silently disappears from the output. Tailwind's utility classes were fine until a CSS-layer ordering change dropped borders from the PDF but not the screen. Inline styles removed a whole class of bug where the preview and the PDF disagreed.&lt;/p&gt;

&lt;h2&gt;
  
  
  The A4 auto-fit problem
&lt;/h2&gt;

&lt;p&gt;An invoice with 3 line items and one with 30 both need to look right on one page. The preview measures its own rendered height and applies a transform scale so content always fits A4, then html2canvas captures at the scaled size. Simple, and it beat every "paginate manually" approach I tried.&lt;/p&gt;

&lt;h2&gt;
  
  
  What client-side actually buys you
&lt;/h2&gt;

&lt;p&gt;No server means no database of invoices, no breach surface, and no privacy policy gymnastics. It also means no server costs, which is why the free tier can be genuinely unlimited instead of a trial in disguise.&lt;/p&gt;

&lt;p&gt;The trade-off: no cross-device sync unless you sign in. That felt like the right default for a tool people use once a month.&lt;/p&gt;

&lt;p&gt;Code: &lt;a href="https://github.com/Ahad-Khan2401/invoice-generator" rel="noopener noreferrer"&gt;https://github.com/Ahad-Khan2401/invoice-generator&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Happy to answer questions about the jsPDF pipeline — it was the fiddliest part by far.&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>showdev</category>
    </item>
  </channel>
</rss>
