Styling
pdfmake makes it possible to style any paragraph or its part:var docDefinition = {
content: [
// if you don't need styles, you can use a simple string to define a paragraph
'This is a standard paragraph, using default style',
// using a { text: '...' } object lets you set styling properties
{ text: 'This paragraph will have a bigger font', fontSize: 15 },
// if you set the value of text to an array instead of a string, you'll be able
// to style any part individually
{
text: [
'This paragraph is defined as an array of elements to make it possible to ',
{ text: 'restyle part of it and make it bigger ', fontSize: 15 },
'than the rest.'
]
}
]
};
Style dictionary
It's also possible to define a dictionary of reusable styles:var docDefinition = {
content: [
{ text: 'This is a header', style: 'header' },
'No styling here, this is a standard paragraph',
{ text: 'Report No. 001', style: 'anotherstyle' }, { text: 'Created Date', style: [ 'header', 'anotherstyle' ] }
{ text: 'This is report body, style: 'textstyle' } ],
styles: {
header: {
fontSize: 22,
bold: true,
alignment: "center",
},
anotherstyle: {
fontSize: 14,
bold:true,
alignment: 'right',
},
textstyle: {
fontSize: 14,
alignment: 'justify',
}
};
Columns
By default paragraphs are rendered as a vertical stack of elements (one below another). It is possible however to divide available space into columns. Note Column content is not limited to a simple text. It can actually contain any valid pdfmake element.var docDefinition = {
content: [
'This paragraph fills full width, as there are no columns. Next paragraph however consists of three columns',
{
columns: [
{
// auto-sized columns have their widths based on their content
width: 'auto',
text: 'First column'
},
{
// star-sized columns fill the remaining space
// if there's more than one star-column, available width is divided equally
width: '*',
text: 'Second column'
},
{
// fixed width
width: 100,
text: 'Third column'
},
{
// % width
width: '20%',
text: 'Fourth column'
}
],
// optional space between columns
columnGap: 10
},
'This paragraph goes below all columns and has full width'
]
};
Tables
var docDefinition = {
content: [
{
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,
widths: [ '*', 'auto', 100, '*' ],
body: [
[ 'First', 'Second', 'Third', 'The last one' ],
[ 'Value 1', 'Value 2', 'Value 3', 'Value 4' ],
[ { text: 'Bold value', bold: true }, 'Val 2', 'Val 3', 'Val 4' ]
]
}
}
]
};
Styling tables
You can provide a custom style for the table. Currently it supports:- line widths
- line colors
- cell paddings
var styles = {
header: {
fontSize: 18,
bold: true,
margin: [0, 0, 0, 10]
},
subheader: {
fontSize: 16,
bold: true,
margin: [0, 10, 0, 5]
},
tableExample: {
margin: [0, 5, 0, 15]
},
tableHeader: {
bold: true,
fontSize: 13,
color: 'black'
}
};
var content = [
{ text: 'Tables', style: 'header' },
{ text: 'A simple table', style: 'subheader' },
'The following table has nothing more than a body array',
{
style: 'tableExample',
table: {
body: [
['Column 1', 'Column 2', 'Column 3'],
['One value goes here', 'Another one here', 'OK?']
]
}
},
{ text: 'noBorders:', fontSize: 14, bold: true, pageBreak: 'before', margin: [0, 0, 0, 8] },
{
style: 'tableExample',
table: {
headerRows: 1,
body: [
[{ text: 'Header 1', style: 'tableHeader' }, { text: 'Header 2', style: 'tableHeader'}, { text: 'Header 3',
style: 'tableHeader' }],
[ 'Sample value 1', 'Sample value 2', 'Sample value 3' ],
[ 'Sample value 1', 'Sample value 2', 'Sample value 3' ],
[ 'Sample value 1', 'Sample value 2', 'Sample value 3' ],
[ 'Sample value 1', 'Sample value 2', 'Sample value 3' ],
[ 'Sample value 1', 'Sample value 2', 'Sample value 3' ],
]
},
layout: 'noBorders'
},
{ text: 'headerLineOnly:', fontSize: 14, bold: true, margin: [0, 20, 0, 8] },
{
style: 'tableExample',
table: {
headerRows: 1,
body: [
[{ text: 'Header 1', style: 'tableHeader' }, { text: 'Header 2', style: 'tableHeader'}, { text: 'Header 3',
style: 'tableHeader' }],
[ 'Sample value 1', 'Sample value 2', 'Sample value 3' ],
[ 'Sample value 1', 'Sample value 2', 'Sample value 3' ],
[ 'Sample value 1', 'Sample value 2', 'Sample value 3' ],
[ 'Sample value 1', 'Sample value 2', 'Sample value 3' ],
[ 'Sample value 1', 'Sample value 2', 'Sample value 3' ],
]
},
layout: 'headerLineOnly'
},
{ text: 'lightHorizontalLines:', fontSize: 14, bold: true, margin: [0, 20, 0, 8] },
{
style: 'tableExample',
table: {
headerRows: 1,
body: [
[{ text: 'Header 1', style: 'tableHeader' }, { text: 'Header 2', style: 'tableHeader'}, { text: 'Header 3',
style: 'tableHeader' }],
[ 'Sample value 1', 'Sample value 2', 'Sample value 3' ],
[ 'Sample value 1', 'Sample value 2', 'Sample value 3' ],
[ 'Sample value 1', 'Sample value 2', 'Sample value 3' ],
[ 'Sample value 1', 'Sample value 2', 'Sample value 3' ],
[ 'Sample value 1', 'Sample value 2', 'Sample value 3' ],
]
},
layout: 'lightHorizontalLines'
},
{ text: 'but you can provide a custom styler as well', margin: [0, 20, 0, 8] },
{
style: 'tableExample',
table: {
headerRows: 1,
body: [
[{ text: 'Header 1', style: 'tableHeader' }, { text: 'Header 2', style: 'tableHeader'}, { text: 'Header 3',
style: 'tableHeader' }],
[ 'Sample value 1', 'Sample value 2', 'Sample value 3' ],
[ 'Sample value 1', 'Sample value 2', 'Sample value 3' ],
[ 'Sample value 1', 'Sample value 2', 'Sample value 3' ],
[ 'Sample value 1', 'Sample value 2', 'Sample value 3' ],
[ 'Sample value 1', 'Sample value 2', 'Sample value 3' ],
]
},
layout: {
hLineWidth: function(i, node) {
return (i === 0 || i === node.table.body.length) ? 2 : 1;
},
vLineWidth: function(i, node) {
return (i === 0 || i === node.table.widths.length) ? 2 : 1;
},
hLineColor: function(i, node) {
return (i === 0 || i === node.table.body.length) ? 'black' : 'gray';
},
vLineColor: function(i, node) {
return (i === 0 || i === node.table.widths.length) ? 'black' : 'gray';
},
// paddingLeft: function(i, node) { return 4; },
// paddingRight: function(i, node) { return 4; },
// paddingTop: function(i, node) { return 2; },
// paddingBottom: function(i, node) { return 2; }
}
}
];
var docDefinition = {
// a string or { width: number, height: number }
pageSize: 'A4',
// by default we use portrait, you can change it to landscape here
pageOrientation: 'portrait', //can change to landscape
// [left, top, right, bottom] or [horizontal, vertical] or just a number for equal margins
pageMargins: [ 40, 60, 40, 60 ],
styles: styles,
content: content,
defaultStyle: {
// alignment: 'justify'
}
};
Lists
pdfMake supports both numbered and bulleted lists:var docDefinition = {
content: [
'Bulleted list example:',
{
// to treat a paragraph as a bulleted list, set an array of items under the ul key
ul: [
'Item 1',
'Item 2',
'Item 3',
{ text: 'Item 4', bold: true },
]
},
'Numbered list example:',
{
// for numbered lists set the ol key
ol: [
'Item 1',
'Item 2',
'Item 3'
]
}
]
};
Headers and footers
Page headers and footers in pdfmake can be: static or dynamic.They use the same syntax:var docDefinition = {
header: 'simple text',
footer: {
columns: [
'Left part',
{ text: 'Right part', alignment: 'right' }
]
},
content: (...)
};
var docDefinition = {
footer: function(currentPage, pageCount) { return currentPage.toString() + ' of ' + pageCount; },
header: function(currentPage, pageCount) {
// you can apply any logic and return any valid pdfmake element
return { text: 'simple text', alignment: (currentPage % 2) ? 'left' : 'right' };
},
(...)
};
Background-layer
The background-layer will be added on every page.var docDefinition = {
background: 'simple text',
content: (...)
};
var docDefinition = {
background: function(currentPage) {
return 'simple text on page ' + currentPage
},
content: (...)
};
Margins
Any element in pdfMake can have a margin:(...)
// margin: [left, top, right, bottom]
{ text: 'sample', margin: [ 5, 2, 10, 20 ] },
// margin: [horizontal, vertical]
{ text: 'another text', margin: [5, 2] },
// margin: equalLeftTopRightBottom
{ text: 'last one', margin: 5 }
(...)
Stack of paragraphs
You could have figured out by now (from the examples), that if you set the content key to an array, the document becomes a stack of paragraphs. You'll quite often reuse this structure in a nested element, like in the following example:var docDefinition = {
content: [
'paragraph 1',
'paragraph 2',
{
columns: [
'first column is a simple text',
[
// second column consists of paragraphs
'paragraph A',
'paragraph B',
'these paragraphs will be rendered one below another inside the column'
]
]
}
]
};
var docDefinition = {
content: [
'paragraph 1',
'paragraph 2',
{
columns: [
'first column is a simple text',
{
stack: [
// second column consists of paragraphs
'paragraph A',
'paragraph B',
'these paragraphs will be rendered one below another inside the column'
],
fontSize: 15
}
]
}
]
};
Images
This is simple. Just use the { image: '...' } node type. JPEG and PNG formats are supported.var docDefinition = {
content: [
{
// you'll most often use dataURI images on the browser side
// if no width/height/fit is provided, the original size will be used
image: 'data:image/jpeg;base64,...encodedContent...'
},
{
// if you specify width, image will scale proportionally
image: 'data:image/jpeg;base64,...encodedContent...',
width: 150
},
{
// if you specify both width and height - image will be stretched
image: 'data:image/jpeg;base64,...encodedContent...',
width: 150,
height: 150
},
{
// you can also fit the image inside a rectangle
image: 'data:image/jpeg;base64,...encodedContent...',
fit: [100, 100]
},
{
// if you reuse the same image in multiple nodes,
// you should put it to to images dictionary and reference it by name
image: 'mySuperImage'
},
{
// under NodeJS (or in case you use virtual file system provided by pdfmake)
// you can also pass file names here
image: 'myImageDictionary/image1.jpg'
}
],
images: {
mySuperImage: 'data:image/jpeg;base64,...content...'
}
};
Page dimensions, orientation and margins
var docDefinition = {
// a string or { width: number, height: number }
pageSize: 'A5',
// by default we use portrait, you can change it to landscape if you wish
pageOrientation: 'landscape',
// [left, top, right, bottom] or [horizontal, vertical] or just a number for equal margins
pageMargins: [ 40, 60, 40, 60 ],
};
- '4A0', '2A0', 'A0', 'A1', 'A2', 'A3', 'A4', 'A5', 'A6', 'A7', 'A8', 'A9', 'A10',
- 'B0', 'B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7', 'B8', 'B9', 'B10',
- 'C0', 'C1', 'C2', 'C3', 'C4', 'C5', 'C6', 'C7', 'C8', 'C9', 'C10',
- 'RA0', 'RA1', 'RA2', 'RA3', 'RA4',
- 'SRA0', 'SRA1', 'SRA2', 'SRA3', 'SRA4',
- 'EXECUTIVE', 'FOLIO', 'LEGAL', 'LETTER', 'TABLOID'
{
pageOrientation: 'portrait',
content: [
{text: 'Text on Portrait'},
{text: 'Text on Landscape', pageOrientation: 'landscape', pageBreak: 'before'},
{text: 'Text on Landscape 2', pageOrientation: 'portrait', pageBreak: 'after'},
{text: 'Text on Portrait 2'},
]
}
Document Metadata
PDF documents can have various metadata associated with them, such as the title, or author of the document. You can add that information by adding it to the document definitionvar docDefinition = {
info: {
title: 'awesome Document',
author: 'john doe',
subject: 'subject of document',
keywords: 'keywords for document',
},
content: 'This is an sample PDF printed with pdfMake'
}