DEV Community

Cover image for Creating PDF from HTML
andris skutans
andris skutans

Posted on

Creating PDF from HTML

In many cases, PHP libraries like TCPDF are used to generate PDFs from HTML. While effective, they come with complex code that’s sometimes difficult to modify. For instance, TCPDF can become slow and overwhelming if you need to make changes. This is why I decided to explore a simpler (another) approach without relying on external PHP libraries.

In this tutorial, I'll show what I did to create a PDF from an HTML element and sending to external PHP file. In external PHP file I can send it to email without using any PHP PDF libraries.

I used JavaScript tools like jsPDF and jsPDF-AutoTable.
At first I will show code that prints PDF from HTML. After will show code that generates PDF and sends to external PHP file.
If there is some simpler (less resources requiring) solution, please, advise.

Step 1: Preparing HTML Content

Created some HTML code. Here’s an example of a content section that I will use to print PDF from browser:

<div id="printArea">
    <div>
        <div>Key Employment Terms</div>
        <p>All fields are mandatory, unless they are not applicable</p>
        <table>
            <tbody>
                <tr>
                    <td>
                        <span>Issued on:</span>
                        <span><input type="text" name="ketsIssued" value="03/02/2025"></span>
                        <br>All information accurate as of issuance date
                    </td>
                </tr>
            </tbody>
        </table>
    </div>
</div>
<button onclick="printDiv()">Print</button>

Enter fullscreen mode Exit fullscreen mode

Here I have an example that includes some text and a table. Next CSS and JS code I will use to generate a PDF of the #printArea div.

Step 2: Setting Up the Print Styles

Using CSS, I can control how content is formatted for printing. The following CSS applies specifically when the page is in print mode:

<style> 
    @media print {
        body * { visibility: hidden; }
        body { counter-reset: page; }
        #printArea, #printArea * { visibility: visible; }
        #printArea { position: absolute; left: 0; top: 0; }
        .btnAdd, button { display: none !important; }
    }
</style>

Enter fullscreen mode Exit fullscreen mode

This CSS ensures that everything on the page is hidden except for the content within the #printArea div.

Step 3: JavaScript to Print the Page

When I click the “Print” button, JavaScript will trigger the print functionality and set the PDF file name dynamically. Here’s the code:

function printDiv() {
    const employeeName = 'SomeName'; // Replace with actual dynamic name
    document.title = `${employeeName}.pdf`; // Set the file name
    window.print(); // Open the print dialog
}
Enter fullscreen mode Exit fullscreen mode

At this point, when I click the print button, the browser will prompt to either print the content or save it as a PDF.

Step 4: Generating a PDF from HTML with jsPDF
Although the browser's built-in print dialog works, there are cases when I need to generate the PDF programmatically and send it via email. For that, I will use jsPDF, a popular library for client-side PDF generation.

  • Include the jsPDF and jsPDF-AutoTable Libraries:
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf-autotable/3.5.31/jspdf.plugin.autotable.min.js"></script>
Enter fullscreen mode Exit fullscreen mode
  • Preloading a Font for Non-Latin Characters: If content includes non-latin characters (such as Chinese, Russian, etc.), jsPDF does not support them by default. To solve this, we can load a TTF font (e.g., DroidSansFallback.ttf), convert it to Base64, and include it in the PDF generation process. Here’s how:

Convert the Font to Base64: Use a tool to convert the .ttf font file into Base64 format. You can find the font and use online converters to do this.

Load the Font via JavaScript:

let cachedFontBase64 = null; // Global variable to store the font

async function loadFontOnce() {
    if (!cachedFontBase64) {
        const response = await fetch("fonts/DroidSansFallbackBase64.txt"); // Path to your Base64 font file
        cachedFontBase64 = await response.text();
    }
    return cachedFontBase64;
}

Enter fullscreen mode Exit fullscreen mode

Step 5: Generate the PDF

Here’s the full JavaScript code to generate a PDF, including handling tables and non-latin characters:

async function generateAndSendPDF() { 
    const doc = new window.jspdf.jsPDF();
    const employeeName = 'SomeName'; // Dynamic employee name
    const filename = `${employeeName}.pdf`; // PDF file name
    const base64Font = await loadFontOnce();

    // Add the font to the PDF document
    doc.addFileToVFS("DroidSansFallback.ttf", base64Font);
    doc.addFont("DroidSansFallback.ttf", "DroidSansFallback", "normal");
    doc.setFont("DroidSansFallback");

    // Add content to the PDF
    doc.text("Employee Details1русский1书、杂志等中区别于图片的)正文,文字材料", 10, 10);
    doc.text("Employee Details Данные о сотрудниках 员工详细信息 員工詳細資訊", 10, 20);
    doc.text("Employee Full Name:", 10, 30);
    doc.text(employeeName + '員工姓名', 80, 30);

    // Add a table
    const tableColumns = ["Name", "Department", "Salary"];
    const tableRows = [
        ["Alice", "HR", "$3,500"],
        ["Bob", "IT", "$4,200"],
        ["Charlie", "Finance", "$5,100"]
    ];
    doc.autoTable({
        head: [tableColumns],
        body: tableRows,
        startY: 40,
        theme: "grid",
        styles: { fontSize: 10 },
        headStyles: { fillColor: [0, 122, 204] }, // Header background color
        alternateRowStyles: { fillColor: [240, 240, 240] } // Row background color
    });

    // Convert to Base64 for email
    const pdfBase64 = doc.output("datauristring").split(',')[1];

    // Send the PDF to PHP via AJAX for email
    fetch("filename.php", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ filename, filedata: pdfBase64 })
    }).then(response => response.text())
      .then(data => { console.log(data); });

    // Open PDF in a new tab (optional)
    window.open(doc.output("bloburl"), "_blank");
}
Enter fullscreen mode Exit fullscreen mode

In file filename.php you can include necessary code to send email.

Conclusion
With this approach, I can generate PDFs directly from HTML content using JavaScript, without needing any external PHP libraries. I can handle tables, non-latin characters, and more—all with a flexible and straightforward solution. Once the PDF is generated, I can send it via email by uploading it to the server.

This solution I plan to use for sending Key Employments Terms and payslips.

What I do not like:

  1. Manually need to code JS for each HTML. Did not find solution to send whole, formatted HTML. There is solution to converting HTML to PDF is using the html2pdf.js library. But it creates image. I need PDF with selectable text.
  2. Need to "include" rather large base64 of TTF file. For example DroidSansFallbackBase64.txt takes around 5 Mb.

Thanks for reading! If you have advises or questions, please write in coments!


And also I share some online tools related with web development. Myself I regularly use Word to HTML converter and Table of Contents Generator.

Hostinger image

Get n8n VPS hosting 3x cheaper than a cloud solution

Get fast, easy, secure n8n VPS hosting from $4.99/mo at Hostinger. Automate any workflow using a pre-installed n8n application and no-code customization.

Start now

Top comments (0)

SurveyJS custom survey software

JavaScript Form Builder UI Component

Generate dynamic JSON-driven forms directly in your JavaScript app (Angular, React, Vue.js, jQuery) with a fully customizable drag-and-drop form builder. Easily integrate with any backend system and retain full ownership over your data, with no user or form submission limits.

Learn more

Instrument, monitor, fix: a hands-on debugging session

Join Lazar for a hands-on session where you’ll build it, break it, debug it, and fix it. You’ll set up Sentry, track errors, use Session Replay and Tracing, and leverage some good ol’ AI to find and fix issues fast.

Tune in to the full event

DEV is partnering to bring live events to the community. Join us or dismiss this billboard if you're not interested. ❤️