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 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.
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
}
}; }
This example demonstrates creating a simple “Hello, World!” PDF using pdfmake:
const pdfDoc = new pdfMake({
Roboto: {normal: new Blob([/* ... */])}
.createPdfKitDocument({
})content: 'Hello, World!'
;
}).pipe(blobStream);
pdfDoc.end();
pdfDoc
// 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.
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
: An array of content blocks. These blocks are the building blocks of your PDF, ranging from simple text strings to complex tables and images. This is arguably the most important property of the DDO.
styles
: An object defining reusable styles for various elements in your document. This allows for consistent formatting and avoids repetitive styling definitions.
pageSize
: Specifies the size of the pages in your PDF (e.g., ‘A4’, ‘Letter’, or custom dimensions).
pageMargins
: Defines the margins (top, right, bottom, left) for each page.
header
: Defines the content of the header for each page (except the first, unless specified otherwise).
footer
: Defines the content of the footer for each page (except the first, unless specified otherwise).
images
: Defines the images used in the document.
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:
A simple string: Represents a single line of text.
An object: Represents more complex elements, such as paragraphs, lists, tables, images, and more. These objects have properties to define their content, style, and layout. For instance, a paragraph content block might have text
, style
, alignment
, and other properties.
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.
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 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.
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'
}
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 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 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.
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.
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.
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.
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.
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, 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.
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:
fontSize
: Sets the font size in points.fontFamily
: Specifies the font family (e.g., ‘Times-Roman’, ‘Helvetica’).bold
: A boolean value (true/false) to enable bold text.italic
: A boolean value (true/false) to enable italic text.color
: Sets the text color (e.g., ‘red’, ‘#FF0000’, or a named color).decoration
: Specifies text decoration such as ‘underline’, ‘lineThrough’, etc.lineHeight
: Sets the line height, typically as a multiplier of the font size.Example:
: {
stylesheader: {
fontSize: 18,
bold: true,
color: 'blue'
,
}bodyText: {
fontSize: 12,
lineHeight: 1.5
} }
Paragraph formatting extends text styling. While you can control many aspects through text object properties, you can also directly control paragraph properties like alignment:
alignment
: Controls text alignment within the paragraph (‘left’, ‘center’, ‘right’, ‘justify’).margin
: Adds margin around the paragraph. You can provide a single value (for all sides) or an array of four values (top, right, bottom, left).Example demonstrating alignment within a paragraph:
{text: 'This is a justified paragraph.',
style: 'bodyText',
alignment: 'justify'
}
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.
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 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’.
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.
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.
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 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',
? { text: 'This is extra content.' } : null
showExtraContent .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.
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.
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 }
{
] }
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 pdfmake applications involves standard JavaScript debugging techniques, along with some pdfmake-specific strategies:
Console Logging: Use console.log()
to inspect the structure of your DDO before it’s passed to pdfMake
. This is vital for identifying errors in data transformations or DDO construction.
Inspecting the Generated PDF: Open the generated PDF in a PDF viewer that allows for inspecting the document structure. This may reveal inconsistencies or unexpected layout issues not apparent through console logging.
Simplify the DDO: If encountering complex issues, simplify your DDO gradually to isolate the problem area. Start with a minimal, working example and incrementally add components until the error is reproduced. This helps pinpoint the faulty part of your code or document definition.
Check for Errors: If using custom fonts, ensure they are correctly loaded and defined. If using images, verify that the image paths are accurate and the images are accessible. Pay attention to error messages reported by the browser’s console or pdfmake itself.
Remember that consulting the official pdfmake documentation and community resources is crucial for resolving more complex issues.
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.
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.
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.
Several common errors arise when working with pdfmake. Here are a few, along with possible solutions:
“Uncaught TypeError: Cannot read properties of undefined…”: This often indicates a problem with accessing properties of objects that are undefined or null. Carefully check your data and ensure all necessary properties exist before attempting to access them. Use conditional checks (e.g., if (myObject && myObject.property)
) to handle cases where properties might be missing.
Incorrect Font Definitions: Errors related to fonts usually stem from incorrect font file paths or missing font definitions in your DDO. Double-check your font file inclusion and ensure they are correctly referenced in the fonts
section of your DDO.
Layout Issues: Unexpected layout problems are frequently caused by incorrect styling, missing or improperly defined page margins, or issues with content block nesting. Carefully review your DDO’s structure, styles, and the content block arrangements to fix layout issues. Simplify your DDO to isolate the problem area if necessary.
Image Loading Errors: Problems with images are common. Ensure that image paths are correct and the images are accessible. Using data URLs for images can sometimes resolve issues related to server-side accessibility.
For large or complex documents, performance becomes crucial. Here are some optimization strategies:
Data Preprocessing: Process and prepare data before creating the DDO. Avoid complex calculations or data transformations within the DDO construction itself, as this reduces runtime performance.
Efficient Data Structures: Use efficient data structures (e.g., arrays instead of objects where applicable) when building the DDO. This improves the speed at which pdfmake processes the data.
Minimize DOM Manipulation: If using pdfmake within a larger web application, avoid unnecessary DOM manipulation during the PDF generation process. This can lead to significant performance improvements, particularly in complex applications.
Asynchronous Operations: If you need to fetch data remotely or perform time-consuming operations before generating the PDF, use asynchronous JavaScript operations (e.g., async/await
or Promises) to avoid blocking the main thread.
Chunking Large Documents: For extremely large documents, consider dividing them into smaller chunks (multiple PDFs, or multiple pages with distinct rendering), then combining them after generation.
Optimize Images: Use appropriately sized images. Large images significantly impact performance. Compressing images before including them in your document helps.
Can I use pdfmake to generate PDFs from a serverless function? Yes, you can use pdfmake within a serverless function (e.g., AWS Lambda, Google Cloud Functions, Azure Functions) as long as you have a Node.js runtime environment, and use an appropriate wrapper library like pdfmake-nodejs
. However, remember that serverless functions have execution time limits, so optimize your code accordingly.
How can I embed fonts within the generated PDF? pdfmake allows for embedding fonts by defining them within the fonts
section of the DDO. You will need to properly include and base64-encode the font files. See the official pdfmake documentation for detailed instructions.
Does pdfmake support RTL (Right-to-Left) languages? pdfmake’s text rendering generally supports RTL languages, but proper styling and text direction handling might need specific configuration within the DDO to ensure correct display.
Can I generate PDFs with different page sizes? Yes, you can customize the page size using the pageSize
property in the DDO (e.g., 'A4'
, 'Letter'
, or custom dimensions).
Remember to consult the official pdfmake documentation and community forums for the most up-to-date information and solutions to specific problems.
DDO (Document Definition Object): The central JavaScript object that defines the structure and content of a PDF document in pdfmake.
Content Block: An individual element within the content
array of the DDO. These blocks represent the visual components of the PDF (text, images, tables, etc.).
Style: A named set of formatting attributes (font size, color, alignment, etc.) that can be applied to content blocks.
Canvas: A content block that allows for drawing lines, rectangles, and other shapes using a simple drawing API.
Point: A unit of measurement used in pdfmake for specifying dimensions and positions. 72 points equal one inch.
Data URL: A string representing the data of a file (e.g., an image) encoded in a specific format, typically Base64.
pdfmake-nodejs: A wrapper library for using pdfmake in a Node.js environment.
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.
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'
}
};
}
.createPdf(documentDefinition).open(); pdfMake
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.