pdfmake - Documentation

What is pdfmake?

pdfmake is a client-side JavaScript library that allows you to generate PDF documents dynamically within a web browser. Unlike server-side solutions, pdfmake doesn’t require a back-end server or specific server-side languages. This makes it ideal for creating PDFs on the fly based on user interactions or data fetched from an API, directly within the client application. It offers a clean and structured approach to document creation, letting you define content using a JSON-like document definition object. This definition object describes the layout, content, styles, and other aspects of your PDF. pdfmake then processes this object to generate the final PDF file, which can be displayed in the browser or downloaded.

Setting up pdfmake

Setting up pdfmake is straightforward. You primarily need to include the pdfmake library in your HTML file. You can download the library from the official repository or use a CDN. Once included, you’ll have access to the pdfMake object. You might also want to include a font definition (such as the default vfs_fonts.js) if you need fonts beyond the default ones. A typical setup would look like this:

<!DOCTYPE html>
<html>
<head>
<title>pdfmake Example</title>
<script src="pdfmake.min.js"></script>
<script src="vfs_fonts.js"></script> </head>
<body>
<script>
  // Your pdfmake code will go here
</script>
</body>
</html>

Remember to replace "pdfmake.min.js" and "vfs_fonts.js" with the correct paths to your downloaded files.

Basic Document Structure

The core of using pdfmake lies in defining a document definition object. This object is a JSON-like structure that describes your PDF’s content. At its simplest, it contains a content array which holds the elements to be displayed in the document. Each element in the content array can be a simple text string, a more complex object defining a paragraph, image, table, or other document element. Other top-level properties in the document definition object can control page margins, page size, and overall document styles. A typical structure looks like this:

const documentDefinition = {
  content: [
    'This is a simple text string.',
    { text: 'This is a paragraph.', style: 'paragraphStyle' }
  ],
  styles: {
    paragraphStyle: {
      fontSize: 12,
      lineHeight: 1.5
    }
  }
};

Hello World Example

This example demonstrates creating a simple “Hello, World!” PDF using pdfmake:

const pdfDoc = new pdfMake({
    Roboto: {normal: new Blob([/* ... */])}
}).createPdfKitDocument({
  content: 'Hello, World!'
});
pdfDoc.pipe(blobStream);
pdfDoc.end();


// Alternative using the older pdfMake (without pdfKit):
// const pdfDoc = new pdfMake({
//   content: 'Hello, World!'
// });
// pdfDoc.createPdf().open();

This code creates a PDF document containing the text “Hello, World!”. Remember that to execute this code successfully, you will need to include the pdfmake.min.js (and possibly vfs_fonts.js) file as explained in the “Setting up pdfmake” section and adapt the code to match whether or not you are using pdfKit. The use of blobStream is necessary for the pdfKit version of the library. For the older versions, createPdf().open() is sufficient. Consult the pdfmake documentation for more details on advanced usage and different methods to generate and handle the PDF.

Core Concepts

Document Definition Object (DDO)

The Document Definition Object (DDO) is the cornerstone of pdfmake. It’s a JavaScript object that comprehensively describes the structure and appearance of your PDF document. The DDO is passed to the pdfMake function to generate the PDF. It’s structured as a hierarchical JSON-like object, allowing you to nest elements and define complex layouts. The DDO usually contains several key properties, including:

Content Blocks

Content blocks are the individual elements within the content array of the DDO. They represent the visual components of your PDF. A content block can be:

Fonts and Styles

pdfmake allows for customization of fonts and styles to enhance the visual appeal of your PDF. Styles are defined in the styles property of the DDO. Each style is an object containing various font properties, like fontSize, fontFamily, bold, italic, color, alignment and more. You can then apply these styles to individual content blocks using the style property.

Defining a custom font requires including the font file and defining it in your DDO using the fonts property. pdfmake supports various font formats. Refer to the pdfmake documentation for detailed instructions on using custom fonts.

Page Layout and Margins

The page layout and margins significantly affect the overall look and feel of your PDF. The pageSize property in the DDO controls the dimensions of each page (e.g., ‘A4’, ‘Letter’, or custom dimensions). The pageMargins property lets you define the margins (top, right, bottom, left) in points or millimeters. You can use a single number for uniform margins or an array of four numbers to specify different margins for each side. Understanding page size and margins is crucial for creating well-formatted PDFs.

Headers and Footers

Headers and footers provide a consistent and informative element across the pages of your PDF. They are defined using the header and footer properties in the DDO. These properties accept content blocks, allowing for text, images, or other elements. You can customize the content and appearance of your headers and footers independently. Note that, by default, the header and footer are not included on the first page. You can customize this behaviour if needed. Using page numbers or other dynamic content in headers/footers will often involve using functions within the DDO or in conjunction with the document generation process.

Basic Elements

Text

Text is the most fundamental element in pdfmake. Simple text can be added directly as a string within the content array of the DDO. For more control over formatting, use a text object:

{ text: 'This is a paragraph of text.', style: 'myStyle' }

Here, 'myStyle' refers to a style defined in the styles section of the DDO. Properties within the text object can include: text, style, fontSize, color, bold, italic, alignment (left, right, center, justify), margin, and more. Line breaks can be added using \n.

{
  text: ['This is a line of text.\n', 'This is another line.'],
  style: 'myStyle'
}

Images

To include images, you need to define them in the images section of the DDO and then reference them in a content block. The images section maps image names to their URLs or data URLs.

const documentDefinition = {
  images: {
    myImage: 'path/to/my/image.jpg' //or a data URL
  },
  content: [
    { image: 'myImage', width: 200 }
  ]
};

Replace 'path/to/my/image.jpg' with the actual path or data URL. The width property controls the image’s width; the height is adjusted proportionally.

Lines and Rectangles

Lines and rectangles provide visual structure and separation within your PDF. They are represented as content blocks:

// Line
{ canvas: [ { type: 'line', x1: 50, y1: 50, x2: 250, y2: 50 } ] }

// Rectangle
{ canvas: [ { type: 'rect', x: 50, y: 100, w: 200, h: 100 } ] }

canvas content blocks allow for drawing. For a line, you specify the starting (x1, y1) and ending (x2, y2) coordinates. For a rectangle, specify the x and y coordinates of the top-left corner, width (w), and height (h). Coordinates are in points. You can adjust the line width and style using additional canvas options (consult the pdfmake documentation for details).

Tables

Tables are created using the table content block. They require a body array, which contains rows (arrays of cells). Each cell can be a string or a complex object with formatting options.

{
  table: {
    body: [
      [ 'Header 1', 'Header 2' ],
      [ 'Row 1, Cell 1', 'Row 1, Cell 2' ],
      [ 'Row 2, Cell 1', 'Row 2, Cell 2' ]
    ]
  }
}

Further customization includes specifying column widths, header styles, cell padding, and more. Refer to the pdfmake documentation for advanced table options.

Lists (Ordered and Unordered)

pdfmake supports both ordered and unordered lists. These are created using the ul (unordered list) and ol (ordered list) content blocks. List items are represented as arrays within the ul or ol array:

// Unordered List
{
  ul: [
    'Item 1',
    'Item 2',
    'Item 3'
  ]
}

// Ordered List
{
  ol: [
    'Item 1',
    'Item 2',
    'Item 3'
  ]
}

Each item can be a simple string or a more complex object allowing for nested lists or additional formatting.

Advanced Elements

Nested Tables

pdfmake allows for creating nested tables, where tables can be contained within other tables’ cells. This is useful for representing hierarchical data. To create a nested table, simply place a table object within a cell of another table. Ensure proper styling and alignment to maintain readability. The inner table will inherit styles from its parent cell unless explicitly overridden.

Complex Layouts with Columns

Achieving complex layouts often involves using columns. While pdfmake doesn’t have a dedicated “column” element, you can simulate column layouts using the columns content block. This block takes an array of content arrays, each representing a column. The content within each column array is laid out vertically.

{
  columns: [
    [ { text: 'Column 1 content' }, { text: 'More Column 1 content' } ],
    [ { text: 'Column 2 content' }, { image: 'myImage', width: 100 } ]
  ]
}

This creates a layout with two columns. The width of each column is determined automatically, distributing the available space. For more fine-grained control over column widths, you can use the width property within the columns object. You can also mix different elements within each column.

Page Breaks and Sections

Controlling page breaks is crucial for well-structured documents. pdfmake provides the pageBreak content block to force a page break at a specific point. For longer documents, consider sectioning your content for better organization and flow. Sections can be implemented by strategically placing page breaks, using headers and footers to distinguish sections, and logically grouping content using content arrays within larger content arrays.

Backgrounds and Watermarks

Adding backgrounds and watermarks enhances the visual appeal and security of your PDF. Backgrounds can be achieved using the canvas element with the type: 'rect' and filling with a color or image. Watermarks usually involve placing a semi-transparent image or text across the entire page, often repeated across multiple pages. Careful positioning and transparency settings are crucial to maintain readability of the main content. Using JavaScript functions to repeat watermarks on each page will be necessary for more complex scenarios.

Annotations

Annotations, such as highlights, underlines, comments, and links, enhance interactivity and readability. pdfmake offers limited direct support for annotations compared to some other PDF libraries. However, you can achieve similar effects using features like links (link property in text objects) or by utilizing the canvas element for custom visual markers like underlines or highlights. For more sophisticated annotations, consider using a post-processing step with a dedicated PDF manipulation library after generating the document with pdfmake. This will often require a server-side component.

Styling and Formatting

Text Styles

Text styles in pdfmake are defined in the styles section of the DDO and applied using the style property within text objects. You can define various properties within a style, such as:

Example:

styles: {
  header: {
    fontSize: 18,
    bold: true,
    color: 'blue'
  },
  bodyText: {
    fontSize: 12,
    lineHeight: 1.5
  }
}

Paragraph Formatting

Paragraph formatting extends text styling. While you can control many aspects through text object properties, you can also directly control paragraph properties like alignment:

Example demonstrating alignment within a paragraph:

{
  text: 'This is a justified paragraph.',
  style: 'bodyText',
  alignment: 'justify'
}

Color and Background Colors

You can control both text color and background color for various elements. Text color is set using the color property within text styles or text objects. Background color can be achieved for elements that support this styling, primarily through the fillColor property within canvas objects or table cell styling.

Fonts and Font Sizes

pdfmake supports various fonts. To use custom fonts, you need to include the font files and define them using the fonts property in your DDO. The fontFamily property in styles or text objects specifies which font to use. fontSize sets the font size in points.

Alignment Options

Alignment applies to text within paragraphs, table cells, and even entire sections (using the alignment property at the top level of the DDO for page content). Available options usually include ‘left’, ‘center’, ‘right’, and ‘justify’.

Customizing Table Styles

Table styles are defined similarly to text styles, but apply to table elements. You can define styles for the entire table, header rows, and individual cells. Properties like fontSize, fontFamily, color, alignment, cellPadding, border, and borderColor can be customized. You can apply styles to table parts using the styles property within the table object:

{
  table: {
    body: [ /* ... */ ],
    styles: {
      header: {
        bold: true,
        fontSize: 14
      }
    }
  }
}

Remember to refer to the pdfmake documentation for the most up-to-date list of styling properties and their usage.

Working with Data

Generating PDFs from JSON Data

A primary strength of pdfmake is its ability to generate PDFs dynamically from data sources, frequently JSON. This involves structuring your JSON data in a way that aligns with the structure expected by pdfmake’s DDO. You’ll typically iterate through your JSON data and build the content array of your DDO programmatically.

For example, if you have JSON representing a list of items:

[
  { "name": "Item 1", "description": "Description of Item 1" },
  { "name": "Item 2", "description": "Description of Item 2" }
]

You’d process this data in your JavaScript code to construct the pdfmake DDO:

const jsonData = [ /* ... your JSON data ... */ ];
const documentDefinition = {
  content: jsonData.map(item => ({
    text: [item.name, item.description].join('\n')
  }))
};

This code iterates through the jsonData array and creates a text content block for each item. More complex data structures would necessitate more sophisticated mapping and potentially the use of tables or other pdfmake elements for better organization.

Data Binding and Templating

While pdfmake doesn’t provide built-in templating engines, you can achieve data binding and templating effects by using JavaScript string manipulation or template literals within your DDO construction. This involves dynamically constructing strings from your JSON data and embedding them within the content blocks.

For instance:

const item = { name: 'My Item', price: 19.99 };
const documentDefinition = {
  content: [`Item Name: ${item.name}\nPrice: $${item.price}`]
};

This approach allows you to embed data directly into your PDF’s content. For more complex templating needs, consider using a client-side JavaScript templating engine alongside pdfmake, though this will increase the complexity of the code.

Dynamic Content Generation

Dynamic content generation goes beyond simple data binding. It involves creating parts of your PDF based on complex logic, calculations, or conditional rendering. This often requires using JavaScript functions within the DDO construction. For example, you might conditionally include sections based on user input or dynamically calculate values to display in the PDF.

Example of dynamic content based on a condition:

const showExtraContent = true;
const documentDefinition = {
  content: [
    'Main content',
    showExtraContent ? { text: 'This is extra content.' } : null
  ].filter(item => item !== null) //Remove null items
};

This example shows or hides a section based on the showExtraContent variable. Functions can be used for far more complex conditional logic and calculations to generate dynamic tables, charts, and other sophisticated elements. Remember that extensive use of dynamic generation might decrease performance. Optimizing your data processing and DDO construction is important for larger datasets or complex documents.

Advanced Techniques

Using JavaScript in pdfmake

pdfmake’s flexibility stems from its ability to integrate with JavaScript. You can use JavaScript functions within your DDO to generate dynamic content, perform calculations, and handle complex logic. Functions can be defined outside the DDO and then referenced within it. This is particularly useful for handling large datasets or conditional content.

Example:

function generateTable(data) {
  // ... your logic to generate the table content from data ...
  return {
    table: {
      body: tableBody
    }
  };
}

const documentDefinition = {
  content: [generateTable(myData)]
};

This example shows a function generating a table dynamically based on input data. Remember that complex functions within the DDO can affect performance. Optimize your functions and consider pre-processing data where feasible.

Creating Custom Elements

While pdfmake provides a rich set of built-in elements, you might need custom elements for specific requirements. You can achieve this by leveraging the canvas element and drawing primitives. The canvas element allows for drawing lines, rectangles, images, and other shapes using a simple drawing API, providing a way to construct visually complex elements not directly supported by pdfmake.

{
  canvas: [
    { type: 'rect', x: 50, y: 50, w: 100, h: 50, fillColor: 'blue' },
    { type: 'line', x1: 50, y1: 100, x2: 150, y2: 100 }
  ]
}

Extending pdfmake Functionality

For advanced needs beyond custom elements, you might consider extending pdfmake’s core functionality. This can involve creating custom document objects, extending the existing styling mechanisms, or even modifying the pdfmake library itself (though this requires a deep understanding of the library’s internal workings and is generally not recommended unless absolutely necessary). Extending pdfmake’s functionality allows creation of a more tailored document generation pipeline, and should be approached cautiously.

Debugging and Troubleshooting

Debugging pdfmake applications involves standard JavaScript debugging techniques, along with some pdfmake-specific strategies:

Remember that consulting the official pdfmake documentation and community resources is crucial for resolving more complex issues.

Deployment and Integration

Client-side PDF Generation

The primary advantage of pdfmake is its client-side PDF generation capability. This means the PDF is generated directly within the user’s web browser, without requiring a server-side component. This simplifies deployment and reduces server load, especially beneficial for applications where many PDFs are generated on demand. The entire process happens within the client’s browser, so only the pdfmake library needs to be included in your web application. The user will then be able to either view or download the generated PDF file through the browser, depending on the chosen method of handling the PDF data.

Server-side PDF Generation (Node.js)

While client-side generation is efficient, some applications might benefit from server-side PDF generation, particularly for scenarios requiring server-side data processing or enhanced security. Node.js, with the appropriate modules, provides a server-side environment to use pdfmake. This typically involves using a library like pdfmake-nodejs which is a wrapper to allow pdfmake to be used within a Node.js environment. The server-side process would receive the required data, build the pdfmake DDO, generate the PDF, and then send the PDF data as a response to the client. This approach is useful when sensitive data needs to be processed server-side to avoid exposing it directly to the client, or when the complexity of the DDO creation necessitates the resources of a server environment.

Integration with Web Frameworks (React, Angular, Vue)

Integrating pdfmake with popular JavaScript frameworks like React, Angular, and Vue involves incorporating the pdfmake library into your application’s component structure. In React, this might involve creating a custom component responsible for generating the PDF. In Angular, you’d likely create a service or component to handle PDF generation. For Vue, you could implement a component or mixin to trigger PDF generation.

The core principle remains consistent across frameworks: you’ll use JavaScript to construct the pdfmake DDO, using the framework’s data binding mechanisms to populate it with application data and trigger PDF generation when appropriate (often based on a user action such as a button click). The generated PDF can then be displayed in a new tab or prompted for download based on the specifics of your application and integration with the relevant framework. The choice of integration method will largely depend on the structure of the application and its overall architecture.

Troubleshooting and FAQs

Common Errors and Solutions

Several common errors arise when working with pdfmake. Here are a few, along with possible solutions:

Performance Optimization

For large or complex documents, performance becomes crucial. Here are some optimization strategies:

Frequently Asked Questions

Remember to consult the official pdfmake documentation and community forums for the most up-to-date information and solutions to specific problems.

Appendix

Glossary of Terms

List of Available Fonts

pdfmake’s default fonts include a set of standard fonts like “Helvetica”, “Times-Roman”, and “Courier”. The availability of additional fonts depends on the fonts included in the vfs_fonts.js file (or other font files you include). You should always consult the most recent version of vfs_fonts.js for the complete list of available fonts. Additionally, you can include custom fonts by embedding them within your project or loading them externally.

Complete Example: Complex Document Generation

This example demonstrates a more complex document generation scenario involving nested tables, images, styling, and headers/footers. Remember to adapt paths to your actual files:

const documentDefinition = {
  pageSize: 'A4',
  pageMargins: [40, 60, 40, 60],
  header: {
    text: 'My Company Report',
    fontSize: 18,
    bold: true,
    margin: [40, 20, 0, 0]
  },
  images: {
    myLogo: 'path/to/mylogo.png'
  },
  content: [
    { image: 'myLogo', width: 100, margin: [40, 20, 0, 0] },
    { text: 'Sales Report - Q3 2024', style: 'header', margin: [0, 20, 0, 0] },
    { text: 'This report summarizes the sales performance for Q3 2024.', margin: [0, 10, 20, 0] },
    {
      table: {
        body: [
          [ { text: 'Product', style: 'tableHeader' }, { text: 'Sales', style: 'tableHeader' } ],
          [ 'Product A', '1000' ],
          [ 'Product B', '1500' ],
          [
            {
              text: 'Product C',
              colSpan: 2,
              style: ['tableHeader', 'bold']
            }, {},
          ],
          [ 'Product C Sub-Item 1', '500' ],
          [ 'Product C Sub-Item 2', '1000' ]
        ],
        widths: [ '*', '*' ]
      }
    }
  ],
  styles: {
    header: {
      fontSize: 16,
      bold: true
    },
    tableHeader: {
      bold: true,
      fontSize: 12,
      color: 'blue'
    }
  }
};

pdfMake.createPdf(documentDefinition).open();

This example showcases a well-structured document with headers, an image logo, a main text section, and a nested table showcasing different styling properties. Remember to replace placeholder content and paths with your own data and adjust styling as needed. This provides a more complex template for building your own documents. Adapt this example to incorporate other elements, styling, and data to meet your specific needs. Remember to handle any errors appropriately and include necessary error handling within your code.