DEV Community

Palks Studio
Palks Studio

Posted on • Edited on

You don’t need a backend to generate quotes

Example of a generated quote (PDF output)

Creating a quote should be simple.

Yet most tools require:

  • account creation
  • email registration
  • server-side storage
  • sometimes even a subscription.

I wanted to try a different approach.

A quote generator that runs entirely in the browser.

No backend.

No API.

No database.

You can test it here:

https://palks-studio.com/fr/generateur-devis

The tool generates a professional PDF quote directly in the browser without sending any data to a server.


Everything runs in the browser

Everything happens client-side.

User fills the form



JavaScript processes the data



PDF is generated locally



Browser downloads the file

No network request is required.

The only external dependency is the jsPDF library.


Generating PDFs directly in JavaScript

The generator relies on jsPDF to build the document directly in JavaScript.

<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js"></script>
Enter fullscreen mode Exit fullscreen mode

Once loaded, creating a PDF is straightforward.

const { jsPDF } = window.jspdf;

const doc = new jsPDF({
  unit: "mm",
  format: "a4"
});
Enter fullscreen mode Exit fullscreen mode

From there, everything can be drawn directly into the document.


The form mirrors the final document

The form mirrors a real quote structure.

It contains:

  • issuer information
  • client information
  • quote metadata
  • service lines
  • totals
  • payment details

Example structure:

<div class="card">

  <div class="card-header">
    <div class="card-header-title">Your company</div>
  </div>

  <div class="card-body">
    <input name="issuer_name" required>
    <input name="issuer_email">
    <input name="issuer_phone">
  </div>

</div>
Enter fullscreen mode Exit fullscreen mode

Each section of the form maps directly to a block inside the generated PDF.


Quotes need flexible line items

Quotes require flexible service lines.

Users can dynamically add or remove rows.

function addLine() {

  lineCount++;

  const row = document.createElement("div");
  row.className = "line-row";

  row.innerHTML = `
    <input name="lines[${lineCount}][desc]">
    <input name="lines[${lineCount}][qty]" type="number">
    <input name="lines[${lineCount}][price]" type="number">
  `;

  container.appendChild(row);

}
Enter fullscreen mode Exit fullscreen mode

Each line contains:

  • description
  • quantity
  • unit price
  • VAT rate

Totals update instantly when values change.


All calculations happen instantly

All calculations are transparent and client-side.

function updateTotals() {

  let subtotal = 0;
  let vatTotal = 0;

  document.querySelectorAll(".line-row").forEach(row => {

    const qty   = parseFloat(row.querySelector('[name*="[qty]"]').value) || 0;
    const price = parseFloat(row.querySelector('[name*="[price]"]').value) || 0;
    const vat   = parseFloat(row.querySelector('[name*="[tva]"]').value) || 0;

    const lineHT = qty * price;

    subtotal += lineHT;
    vatTotal += lineHT * vat / 100;

  });

  const total = subtotal + vatTotal;

}
Enter fullscreen mode Exit fullscreen mode

The UI immediately displays:

  • Subtotal
  • VAT
  • Total amount

before the PDF is generated.


Turning form data into a document

When the user confirms, the script builds the document.

const { jsPDF } = window.jspdf;

const doc = new jsPDF({
  unit: "mm",
  format: "a4"
});
Enter fullscreen mode Exit fullscreen mode

Then the script draws the document:

  • header
  • issuer block
  • client block
  • service table
  • totals
  • notes
  • footer

Example:

doc.text("QUOTE", 18, 30);
doc.text(quoteNumber, 18, 38);
Enter fullscreen mode Exit fullscreen mode

Every field comes directly from the form inputs.


Keeping the layout stable

PDF layout can break when text becomes longer than expected.

To prevent layout issues, the generator wraps text dynamically.

doc.splitTextToSize(text, maxWidth);
Enter fullscreen mode Exit fullscreen mode

Each block calculates its own height before being drawn.

This prevents overlapping elements and keeps the layout stable.


Why a backend is unnecessary here

For this type of tool, a backend is often unnecessary.

Running everything in the browser provides several advantages.

Privacy.

No data is transmitted to any server.

Simplicity.

No authentication, no database, no API.

Lightweight hosting.

The entire generator is essentially a single HTML page.

It can run on:

  • static hosting
  • GitHub Pages
  • any simple web server

What this approach does not solve

This approach also has some limitations.

There is no:

  • quote history
  • client management
  • automated emailing
  • electronic signature workflow

But for generating quick quotes, it works extremely well.


What this tool is designed for

The goal was not to build a SaaS product.

The goal was to build a tool that is:

  • simple
  • frictionless
  • immediately usable

No login.

No tracking.

No data collection.

Just a form and a downloadable PDF.


Try it yourself

You can test it here:

https://palks-studio.com/fr/generateur-devis

It works on:

  • desktop
  • mobile
  • any modern browser

Sometimes simpler is better

Modern web tools often become unnecessarily complex.

For some use cases, a simple client-side application is more than enough.

A single HTML file with JavaScript can already provide:

  • a structured form
  • dynamic calculations
  • professional PDF generation

Sometimes simplicity is the best solution.

https://github.com/Palks-Studio/free-quote-generator


https://palks-studio.com

Top comments (0)