How to Handle Links in html-to-pdfmake: A Complete Guide
The html-to-pdfmake library converts HTML <a> tags into PDFMake links by extracting the href attribute and applying it recursively to all child nodes using the internal setLink helper function.
When converting HTML to PDF documents, handling hyperlinks correctly ensures your PDFs remain interactive and navigable. The html-to-pdfmake library processes anchor tags systematically, supporting both external URLs and internal PDF destinations while preserving links on complex nested content like images or styled text.
How html-to-pdfmake Processes Anchor Tags
The conversion engine in index.js handles anchor elements through a dedicated case "A" block (lines 550-574). When the parser encounters an <a> tag, it extracts the href attribute using element.getAttribute("href") and passes both the accumulated content object and the URL to the setLink helper function.
The setLink Helper Function
The setLink function operates recursively to ensure links apply to every leaf node within the anchor:
- Array processing: When
pointer.textis an array, each child element is processed individually withsetLink, ensuring nested structures like<a><strong>text</strong></a>retain the link property on every component. - Stack handling: For elements containing a
stack(PDFMake's structure for complex children), each stack item receives the link treatment recursively. - Leaf node assignment: For terminal nodes (plain text or images), the function assigns either
pointer.link = hreffor external URLs orpointer.linkToDestination = href.slice(1)for internal anchors starting with#.
If an anchor contains no visible text, the function creates a placeholder {text:''} object to maintain the clickable area.
Internal vs External Links
The library distinguishes between internal document destinations and external URLs through simple string inspection of the href attribute.
External links (any href not starting with #) are stored in the link property of the PDFMake node. Internal links (anchors beginning with #) trigger the linkToDestination property, with the hash symbol stripped to reference the target ID within the PDF document.
// External link example
const pdfDef = htmlToPdfMake(
'<p>Visit <a href="https://example.com">our site</a> for details.</p>',
{ window }
);
// Generates: { text: 'our site', link: 'https://example.com' }
// Internal link (PDF destination)
const pdfDef2 = htmlToPdfMake(
'<h1 id="title">Title</h1><a href="#title">Back to top</a>',
{ window }
);
// Generates: { text: 'Back to top', linkToDestination: 'title' }
Handling Complex Nested Content
Links often wrap non-text elements like images or mixed formatting. The recursive setLink implementation ensures these structures remain clickable in the final PDF.
Images Inside Anchors
When an anchor wraps an image element, the setLink function traverses to the image leaf node and applies the link property directly to the image object:
const pdfDef3 = htmlToPdfMake(
'<a href="https://example.com"><img src="logo.png"></a>',
{ window, imagesByReference: false }
);
// Generates: { image: 'logo.png', link: 'https://example.com' }
Mixed Inline Content
For anchors containing styled text (such as <strong> or <em> tags), the library ensures every text fragment carries the link property. The unit tests in test/unit.js (line 231) verify that mixed content like <a href="..."><strong>Bold</strong> text</a> correctly applies the link to both the bold segment and the regular text.
Source Code Reference
The link handling logic resides in two primary locations within the repository:
index.js(lines 550-574): Contains thecase "A"block that initiates link processing and thesetLinkhelper function implementation.test/unit.js(lines 212, 220, 231): Unit tests validating external link extraction, image wrapping, and nested content handling.
The setLink function specifically handles the recursive propagation of link properties through arrays, stacks, and leaf nodes, ensuring consistent behavior across all anchor element variations.
Summary
- Link extraction: The parser captures
hrefattributes from<a>tags inindex.jsand passes them to thesetLinkhelper. - Recursive application:
setLinktraverses nested structures (arrays, stacks, text nodes) to ensure every leaf receives the link property. - External vs internal: URLs become
linkproperties; anchors starting with#becomelinkToDestinationwith the hash removed. - Complex content: Images and styled text within anchors retain clickable links through recursive processing.
- Testing: Unit tests in
test/unit.jsverify correct link generation for text, images, and mixed content scenarios.
Frequently Asked Questions
How does html-to-pdfmake handle external versus internal links?
External links (standard URLs) are stored in the link property of the PDFMake node, while internal links (href values starting with #) use the linkToDestination property with the hash symbol stripped. This distinction allows PDF viewers to handle external URLs in a browser and internal anchors as document navigation.
Can I put images inside links using html-to-pdfmake?
Yes, the library fully supports wrapping images with anchor tags. The setLink function recursively processes the DOM structure and applies the link property directly to the image leaf node, ensuring the image remains clickable in the generated PDF.
What happens if an anchor tag has no text content?
If an <a> tag contains no visible text (for example, it only wraps an image or is empty), the setLink function creates a placeholder text node {text:''} to maintain the clickable area. This ensures the link exists in the PDF structure even without textual content.
Does html-to-pdfmake preserve CSS styling on links?
Yes, after the link property is attached via setLink, the conversion pipeline continues through the applyStyle function (also in index.js), which processes any CSS classes or inline styles present on the <a> element. This means color, font-weight, and other visual properties apply alongside the interactive link behavior.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →