pdfmake: PDF download in JavaScript (React)

A package called "pdfmake" enables pdf creation/download on front-end without any backend interaction. It would kick out the print css style from your app.

Environment

React 16.13.1
TypeScript 4.0.2
pdfmake 0.1.68

pdfmake

Official site(pdfmake

Try playground to understand how it works.

Install

yarn add pdfmake

Example

This time let's make an employee list downloadable in pdf format using pdfmake.

EmployeeList.tsx

import { getPdfOptions } from '../../domain/employee';
import { Employee } from '../../typings';
import pdfMake from 'pdfmake/build/pdfmake';
import pdfFonts from 'pdfmake/build/vfs_fonts';

pdfMake.vfs = pdfFonts.pdfMake.vfs;

export function Employee(props: any) {
  ...
  // In real world, this would be from redux state or aync fetch.
  const employeeList: Employee[] = [
    { id: 'xxx', name: 'sample', email: 'test@mail.com', designation: 'Japan', department: 'Sample Dept.', age: 22, address: 'sample address #3333', contact: '11110000011' },
    { ... },
    { ... },
  ];

  const onClickPdfMakeHandler = async () => {
    const options = getPdfOptions(employeeList);
    const d = new Date();
    const date = `${d.getDate()}_${d.getMonth()+1}_${d.getFullYear()}`

    pdfMake.createPdf(options).download(`Employee_list_${date}.pdf`);
  }
  ...

  return (
    ...
    <button onClick={onClickPdfMakeHandler}
    ...
  )
}

employee.ts

import _ from 'lodash';

export const getPdfOptions = (employeeList: Employee[]): any => {
  const keys = ['fullName', 'email', 'employmentType', 'designation', 'department', 'age', 'address', 'contact', 'joinDate'];
  const excludedKeys = ['id', 'updatedAt', 'createdAt', 'salary', 'rate', 'fixedRate', 'commission'];

  const records = employeeList.map(employee => {
    return _.compact(keys.map(key => {
      if (excludedKeys.includes(key)) {
        return null;
      }
      return employee[key] ?? '-';
    }));
  });

  return {
    info: {
      title: 'Employee list',
    },
    pageSize: 'A4',
    pageOrientation: 'landscape',
    footer: function(currentPage: number, pageCount: number) {
      return [
        { text: `Employee Management Sytem - ${currentPage.toString()} of ${pageCount}`, alignment: 'right', fontSize: 10, color: '#aaa', margin: [ 0, 0, 30, 10] }
      ]
    },
    content: [
      { text: 'Employee List', margin: [ 0, 16 ], fontSize: 16, bold: true },
      {
        layout: 'lightHorizontalLines',
        fontSize: 10,
        table: {
          // headers are automatically repeated if the table spans over multiple pages
          // you can declare how many rows should be treated as headers
          headerRows: 1,
          body: [ keys, ...records],
        }
      },
    ],
  }
}

For more details, please refer to the offical document.