DEV Community

Ethan from reportgen.io
Ethan from reportgen.io

Posted on

Level Up Your PDF Game: From 1998 to Stunning in 15 Minutes

You're shipping reports, invoices, or data exports as PDFs. And they look like they were built in 1998. That might fly internally, but the moment you're sending them to clients, investors, or partners, it reflects directly on your brand.

Bad design isn't neutral. It kills trust.

With reportgen.io, you can generate stunning PDFs using modern CSS, Tailwind, and Chart.js - without turning your dev team into a design agency.

Here's how to go from "ugh" to "damn" in 15 minutes.


🚧 Step 1: Basic CSS – Full Control, Old School

If you want tight control and don't mind some manual work, you can write vanilla CSS. Think of this like hand-coding an HTML email.

<!-- sample invoice template -->
<style>
  body { font-family: Arial; padding: 20px; }
  .invoice { max-width: 600px; margin: auto; border: 1px solid #ccc; padding: 20px; }
</style>
<div class="invoice">
  <h1>Invoice</h1>
  <table>...</table>
</div>
Enter fullscreen mode Exit fullscreen mode

Pros:

  • No dependencies.
  • Predictable rendering.

Cons:

  • Verbose.
  • No design system or utility classes.

⚑ Step 2: Tailwind – Fast, Consistent Styling

Already using Tailwind in your app? Great! Carry that system into your PDFs. Just inline the CDN or use a local build.

<script src="https://cdn.tailwindcss.com"></script>
<div class="max-w-xl mx-auto bg-white p-6 rounded shadow">
  <h1 class="text-2xl font-bold mb-4">Invoice</h1>
  <table class="w-full text-sm">...</table>
</div>
Enter fullscreen mode Exit fullscreen mode

Pros:

  • Speed. Utility-first styling is fast.
  • Reusability. Copy-paste styles from your app.

Caveat:
Tailwind must be inlined as external network calls won't work in the PDF engine.


πŸ“Š Step 3: Add Dynamic Charts with Chart.js

Static reports are fine. But data-driven PDFs with live charts? That's next-level.

<canvas id="myChart"></canvas>
<script>
  new Chart(document.getElementById('myChart').getContext('2d'), {
    type: 'bar',
    data: { labels: [...], datasets: [...] }
  });
</script>
Enter fullscreen mode Exit fullscreen mode

Yes, this renders directly into your PDF. No screenshotting, no hacks.

Want to make it dynamic? Use EJS (or any template engine):

<script>
  const data = <%- JSON.stringify(myData) %>;
</script>
Enter fullscreen mode Exit fullscreen mode

Then inject your data via the reportgen.io API.

{
  "html_template": "...",
  "data": { "myData": [100, 200, 300] },
  "engine": "ejs"
}
Enter fullscreen mode Exit fullscreen mode

πŸ“„ Learn More: Read the Full Guide β†’


🧰 Docs & GitHub reference


Final Take

You built a great product. Don't let your PDFs be the weakest link.

With reportgen.io, you can generate client-ready, visually impressive, dynamic PDFs in minutes, not days.

Make your output match your quality.


πŸ‘‰ Ready to make your PDFs not suck? Try it free at reportgen.io
You get 150 reports for free each month, no credit card required.

Top comments (0)