How to Handle Custom HTML Tags in html-to-pdfmake: A Complete Guide
Use the customTag callback option to intercept unknown HTML elements and transform them into valid PDFMake nodes before they reach the parser's default handler.
The html-to-pdfmake library converts standard HTML into PDFMake document definitions, but it cannot natively recognize every custom element or specialized tag you might use. When the parser encounters an unsupported tag, it triggers the customTag callback defined in your options object, allowing you to inject custom logic at the default handler in index.js lines 588–590.
How the customTag Callback Works
When htmlToPdfMake processes an HTML element that does not match any built-in case in the parseElement switch statement, execution falls through to the default branch. According to the source code at [index.js lines 588–590](https://github.com/aymkdn/html-to-pdfmake/blob/master/index.js#L588-L590), the library checks for options.customTag and invokes it using .call(this), binding the internal parser instance to your function.
Callback Parameters
The customTag function receives three parameters:
| Parameter | Type | Description |
|---|---|---|
element |
DOM Node | The native HTML element being processed |
ret |
Object | The current PDFMake fragment (may be empty) |
parents |
Array | Ancestor nodes for style inheritance |
Your callback may modify ret to add text, styles, or custom PDFMake keys, and must return the updated object. Because the function is called with call(this), you have access to internal helper methods such as applyStyle and parseStyle.
Practical Implementation Examples
Basic Custom Tag Handler
The following example demonstrates handling a simple <custom-tag> element by replacing it with a paragraph containing static text:
const html = `<custom-tag></custom-tag>`;
const result = htmlToPdfmake(html, {
customTag({ element, ret }) {
if (element.nodeName === 'CUSTOM-TAG') {
// Replace the unknown tag with a paragraph containing custom text
ret = { text: 'This is content inserted by a custom tag.' };
}
return ret;
}
});
console.log(result);
// → { text: 'This is content inserted by a custom tag.' }
QR Code Generator Implementation
This advanced example from the official documentation shows how to transform a <code typecode="QR"> element into a PDFMake QR code node:
const html = `<code typecode="QR" style="foreground:black;background:yellow;fit:300px">
texto in code
</code>`;
const pdfDef = htmlToPdfmake(html, {
customTag(params) {
const { element, ret, parents } = params;
// Only act on our special <code> element
if (ret.nodeName === 'CODE') {
// Apply inherited styles first
ret = this.applyStyle({ ret, parents: parents.concat([element]) });
// Extract the inner text that will become the QR payload
ret.qr = ret.text[0].text; // ← QR content
delete ret.text; // QR node does not need regular text
// Mark the node so PDFMake knows it is a QR
ret.nodeName = 'QR';
ret.style = (ret.style || []).concat('html-qr');
}
return ret;
}
});
The resulting definition contains {nodeName:'QR', qr:'texto in code', style:['html-qr']}, which PDFMake renders as a QR code when using a compatible QR extension.
Wrapping Third-Party Widgets
Handle proprietary widget tags by extracting attributes and converting them to styled PDFMake elements:
const html = `<my-widget data-value="42"></my-widget>`;
const pdfDef = htmlToPdfmake(html, {
customTag({ element, ret, parents }) {
if (element.nodeName === 'MY-WIDGET') {
// Use the data-value attribute to create a table cell with custom background
ret = {
background: '#f0f0f0',
text: `Widget value: ${element.getAttribute('data-value')}`
};
// Re‑apply styles from ancestors (margin, alignment, etc.)
ret = this.applyStyle({ ret, parents });
}
return ret;
}
});
Accessing Internal Parser Methods
Because customTag is invoked using options.customTag.call(this, ...), the callback executes within the context of the parser instance. This binding gives you access to internal helper methods such as:
this.applyStyle({ ret, parents })– Applies inherited CSS classes and inline styles to your custom nodethis.parseStyle(styleString)– Parses CSS style strings into PDFMake-compatible style objectsthis.computeStyle(style)– Computes final styles after processing
Leveraging these methods ensures your custom tags respect the same styling cascade as standard HTML elements.
Key Source Files Reference
| File | Purpose |
|---|---|
[index.js](https://github.com/aymkdn/html-to-pdfmake/blob/master/index.js) |
Core parser; customTag hook resides in the default branch of parseElement (lines 588–590) |
[README.md](https://github.com/aymkdn/html-to-pdfmake/blob/master/README.md) |
Official documentation of the customTag option (lines 38–50) |
[example.js](https://github.com/aymkdn/html-to-pdfmake/blob/master/example.js) |
Usage examples that can be extended with customTag callbacks |
[browser.js](https://github.com/aymkdn/html-to-pdfmake/blob/master/browser.js) |
Browser bundle supporting identical customTag functionality |
Summary
- The
customTagcallback inhtml-to-pdfmakeintercepts unknown HTML elements during the parsing phase atindex.jslines 588–590. - It receives the DOM element, current PDFMake fragment (
ret), and parent nodes for style inheritance. - The callback runs with parser context (
this.applyStyle, etc.), allowing reuse of internal styling logic. - Return a modified PDFMake node to replace the default handling of custom tags.
- Works identically in Node.js (via
jsdom) and browser (viaDOMParser) environments.
Frequently Asked Questions
What happens if I don't define a customTag handler?
When the parser encounters an unrecognized tag without a customTag callback defined, it processes the element's children but returns an empty object for the tag itself. This means custom tags effectively disappear from the final PDF output unless you explicitly handle them.
Can I override standard HTML tags using customTag?
Yes. While customTag primarily handles unknown tags reaching the default branch, you can intercept standard tags by inspecting the ret.nodeName or element.nodeName inside your callback. However, for modifying behavior of built-in tags, preprocessing the HTML or using the styles option is often cleaner.
How do I access element attributes in my custom handler?
The element parameter passed to your callback is a native DOM node, so you can use standard DOM methods like element.getAttribute('data-value'), element.hasAttribute('typecode'), or element.attributes to inspect HTML attributes and drive conditional logic in your PDF generation.
Is the customTag callback supported when using the browser bundle?
Yes. The customTag functionality works identically in both Node.js and browser environments because the core parsing logic in index.js is environment-agnostic. Whether you load the library via require() in Node or include browser.js in a <script> tag, the customTag option is available in the options object passed to htmlToPdfmake.
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 →