Create PDF from HTML content
  • 14 Jun 2023
  • 3 Minutes to read
  • Contributors
  • Dark
    Light

Create PDF from HTML content

  • Dark
    Light

Article Summary

General

The custom-js-utils function CfgrUtils.convertHtmlToPdf allows you to create a fully custom PDF, based on any valid HTML input.
This can be useful for creating offers, a bill of material or similar.

Minimum requirements

  • Resource component of type Document with a pdf, which acts as a placeholder and will be overwritten
    • When creating the component, the checkbox User can upload his own resources must be checked
  • custom-js project (based on the .template-project in your repository)
  • A string with valid html
    • Can be generated anywhere, as long as it's available in custom-js afterwards. (components & hive rules, custom-js function, etc.)

Creating your first PDF

  1. Create a resource component of type Document and check User can upload his own resources
  2. Add a placeholder pdf to the Documents
    image.png
  3. Create a value component which holds the url of the pdf
    • Rule: OfferPdf.myPdf.Url
  4. Add the following code inside the CfgrUtils.onCfgrReady of your custom-js project
    • Change the component & resource names as needed
CfgrUtils.onCfgrReady(async () => {
  const myResourceName = 'myPdf';
  const myHtml = '<!DOCTYPE html><html><body>Hello World!</body></html>';
  CfgrUtils.convertHtmlToPdf(CmpNames.OfferPdf, myResourceName, myHtml);
});

Result

When you run this project, a pdf is immediately created and you can retrieve and open the url from the value component we created earlier.
image.png

Retrieve the updated pdf url

Although the CfgrUtils.convertHtmlToPdf returns a Promise it's not guaranteed that the url of the pdf got updated yet.
Instead, the recommended way is to create a component whose rule returns the url of the pdf and we wait for this component to change.

CfgrUtils.convertHtmlToPdf(CmpNames.OfferPdf, myResourceName, myHtml);
await CmpUtils.waitCmpValueChanged(CmpNames.OfferPdfUrl);
// ... retrieve the new url

This might change in the future so that CfgrUtils.convertHtmlToPdf can be awaited directly.

Creating the HTML

Understanding the tech

At it's very base the generated PDF is very similar to the result of the "Print" feature in your browser.
This also means that you can build and preview your basic layout simply by editing a html-file in a text-editor, then open it in the Chrome browser and press Ctrl+P (shortcut for Print).
image.png

Page layout

CSS provides special selectors & rules to format your html specifically for printing.
Because there exist plenty of articles on the internet we only list some keywords and links here:

  • @page: Overall page formatting like size, margin, etc.
  • page-break-*: Control where a page should (or should not) break and start a new page

Html2PdfOptions

It's also possible to provide options like format, margin, etc. when calling CfgrUtils.convertHtmlToPdf.
For details see Html2PdfOptions.

Header & Footer

To show a header or footer on every page you can pass individual html-strings to the convertHtmlToPdf function.
The body, header and footer don't share their styles and must be defined individually!

Unfortunately there's an issue with sizes (e.g. font-size, margins, ...) so that they are interpreted wrong. This is a bug in the underlying tech so the only workaround is to test & find values which match as close as possible.

CfgrUtils.convertHtmlToPdf(CmpNames.OfferPdf, 'pdf', bodyHtmlString, {
    displayHeaderFooter: true,
    footerTemplate: footerHtmlString,
    headerTemplate: headerHtmlString,
  });

Page numbers and similar

These only work in the header & footer! They have no effect inside the body.

Specific css classes can be used to inject auto-generated values into the PDF.
To do so, simply create a html-tag with one of the css classes stated below.

Possible values (css classes)

  • date - formatted print date
  • title - document title
  • url - document location
  • pageNumber - current page number
  • totalPages - total pages in the document

Example usage

Page <span class="pageNumber"></span> of <span  class="totalPages"></span> 

See also Puppeteer PDFOptions.headerTemplate

Troubleshooting

Puppeteer

This whole feature is based on the library Puppeteer.
In case of any troubles or unclear results you may find answers by searching their docs or using the keyword Puppeteer in your search engine.

Images or fonts inside the header or footer aren't working

External links aren't supported. Instead they have to be inserted directly into the html.

  • If the image is available as SVG, simply add it like any other tag
  • Other images can be converted to a base64 string and be inserted like this:
    • Example: <img src="data:image/png;base64, iVBORwAAAAUAFCAYAAA......."/>
    • For larger base64 strings it's recommended to store them inside a TextAsset

Wrong size/scale inside the header or footer

Unfortunately there exists a known bug in the underlying tech.
See info section of Header & Footer for details.


Was this article helpful?

What's Next