How to display mixed content in pdfmake pdf
What is pdfmake
pdfmake is a fully javascript-based library that can be used for the creation of custom downloadable PDF files on demand. A possible use case of pdfmake is for example, if you have a ‘Download’ button in your UI and you want a new pdf file to be downloaded on the client-side UI without any backend API call.
pdfmake has its testing editor which they call a playground. You can find some basic examples and test your code there. Here is the link to pdfmake playground.
What are we solving here?
It is easy in pdfmake to display simple texts in the file. It is also simple to display a single image in the generated PDF. But how to display a text along with an image as a single unit on the output pdf?
What will we create?
We will create a simple table with only one column and only two rows. It will simply look like the one below. In it, we will add a header in the first row and a single unit of content that comprises one text and an svg smiley.
Show me the code
Let’s start step by step. If we analyze the problem statement here, we can see that we have to achieve two things. The first is a table with two rows and one column. The second is a cluster of text and an svg as a single unit.
Let us create the table with an empty body first. The JSON will look like the below
{ content: [ { style: 'tableExample', table: { body: [ ] } } ] }
Next, we will create two rows and one column.
['Column 1'], ['Cell 1']
As you are already familiar we have to write each row inside [ ]. Now we have two such rows and each row contains one column.
Therefore our final table structure with two rows and one column is as below
{ content: [ { style: 'tableExample', table: { body: [ ['Column 1'], ['Cell 1'] ] } } ] }
Now it will look like the below image in the playground
Here comes our target element. To make things easy, we have created one svg element using the free svg editor provided by W3Schools.
Now let us try to insert the svg along with a sample text replacing the ‘Cell 1’.
As you have already realized we have to place our code inside the [ ], and there is already a text showing up as ‘Cell 1’. But we can not display a text with an svg element as is, because we have to explicitly inform the pdfmake library that it should consider our svg text as an svg element instead and try to draw it in the pdf.
To instruct pdfmake library about the svg element we have to use ‘svg’ tag below
['Cell 1', { svg: '<svg width="50" height="30" xmlns="http://www.w3.org/2000/svg"> <rect width="100%" height="100%" fill="blue" /><text x="20" y="18" fill="white">:)</text></svg>' } ]
If you try the above code in the playground then you will find that the output pdf is not showing at all! What went wrong?
Notice that in the header row, we had only one element but here in the second row we have added two elements comma-separated. That translates to two columns. We can make it as a single column by enclosing them in parenthesis like { }. So our latest changes updates to as below
[ {'Cell 1', svg: '<svg width=50 height=30 xmlns=http://www.w3.org/2000/svg> <rect width=100% height=100% fill=blue /><text x=20 y=18 fill=white>:)</text></svg>' } ]
But this will still throw an error in the playground because it is not a valid JSON structure. Now, let us think along the lines of JSON structure and standard coding practice. That will resolve our basic errors. Let us add a ‘text’ tag in it as below
[{text: 'Cell 1', svg: '<svg width="50" height="30" xmlns="http://www.w3.org/2000/svg"> <rect width="100%" height="100%" fill="blue" /><text x="20" y="18" fill="white">:)</text></svg>' } ]
Now we have the correct JSON structure. The playground is also not complaining about it. But still, we can not see our svg smiley!
Well, to show the mixed content as a single unit, we have to use the ‘stack’ tag here as below.
stack:[{ }, { }]
Now, I hope you have understood the basic structure of the ‘stack’ tag element. Inside each { } you can write your content below
stack:[ {text: 'Below is a svg smiley'}, {svg: '<svg width="50" height="30" xmlns="http://www.w3.org/2000/svg"> <rect width="100%" height="100%" fill="blue" /><text x="20" y="18" fill="white">:)</text></svg>'} ]
In the light of the above structure, the full working JSON structure is as below
{ content: [ { style: 'tableExample', table: { body: [ ['Column 1'], [ { stack: [ { text: 'Below is a svg smiley'}, { svg: '<svg width="50" height="30" xmlns="http://www.w3.org/2000/svg"> <rect width="100%" height="100%" fill="blue" /><text x="20" y="18" fill="white">:)</text></svg>'} ] } ] ] } } ] }
Great! Now we see the output as below
One last point, why do we write the ‘stack’ tag enclosed in parenthesis { } like below?
{stack:[{ }, { }]}
The answer is, that you can notice that the row contents are array type. We write row content within [ ]. Therefore, [stack:[]] is not a correct JSON type, right? That is the reason we have to write it in the ‘array of object’ type to conform with the JSON structure. The good and easy part of pdfmake is that you can resolve some of the issues and understand them by using the common sense of JSON structure. And not to forget, the amazing pdfmake playground is the best place before you finalize the code.