How to Use the customTag Function in html-to-pdfmake: A Complete Guide
The customTag function in html-to-pdfmake acts as a callback hook that intercepts HTML elements without native handlers, allowing you to transform them into custom PDFMake nodes by modifying and returning the ret object.
The aymkdn/html-to-pdfmake library converts HTML strings into PDFMake-compatible definition objects by walking the DOM node-by-node. When the parser encounters tags that lack built-in handlers—such as custom web components or specialized markup—you can use the customTag option to inject your own conversion logic directly into the processing pipeline.
What Is the customTag Function?
The customTag function is an optional callback passed through the options object to htmlToPdfmake(). According to the source code in index.js at lines 88-91, the parser invokes this function whenever it encounters a tag without a native handler:
if (options && typeof options.customTag === "function") {
// handle custom tags
ret = options.customTag.call(this, {
element: element, // the raw DOM element
parents: parents, // array of ancestor elements (for style inheritance)
ret: ret // the current PDFMake node created so far
});
}
This hook executes after the generic element processing but before the final reduction step. This timing allows you to leverage any base properties already populated—such as ret.text or ret.style—while still adding PDFMake-specific attributes that the library does not automatically generate from standard HTML.
customTag Function Signature and Parameters
The callback receives a single object parameter containing three key properties:
element— The raw DOM element being processed. Accesselement.nodeNameto identify the tag (note: uppercase in standard DOM) and use standard DOM methods likeelement.getAttribute()orelement.textContentto extract data.parents— An ordered array of ancestor elements. Use this array to understand nesting context or inherit styles from parent containers.ret— The PDFMake node object generated so far for this element. Modify this object directly to change the output structure, content, or styling.
The function must return the ret object (modified or unmodified) to ensure the parser continues with the correct node definition. Returning null or an empty object will effectively skip processing for that element.
Because the callback uses .call(this, ...), the function is bound to the parser instance. This binding grants access to internal methods such as this.applyStyle(), which you can use to resolve inherited CSS styles before applying custom transformations.
Practical Examples
Handling Simple Custom Tags
Convert a non-standard <my-tag> element into styled static text:
const html = `<p>Hello <my-tag></my-tag> world!</p>`;
const result = htmlToPdfmake(html, {
customTag: function ({ element, ret }) {
if (element.nodeName === 'MY-TAG') {
// Replace the custom element with static content
ret.text = '🌟 Custom Content 🌟';
ret.style = ['custom-tag'];
}
return ret;
}
});
When the parser encounters MY-TAG, the callback detects the node name, injects emoji text, applies a custom style array, and returns the modified node for inclusion in the final PDF definition.
Converting Elements to QR Codes
Transform a <code> element with specific attributes into a PDFMake QR code node, as demonstrated in the official README:
const html = `
<code typecode="QR" style="foreground:black;background:yellow;fit:300px">
texto in code
</code>
`;
const pdfDef = htmlToPdfmake(html, {
customTag: function (params) {
let { element, ret, parents } = params;
if (ret.nodeName === 'CODE') {
// Apply inherited styles first using the parser's internal method
ret = this.applyStyle({
ret,
parents: parents.concat([element])
});
// Extract the text content for the QR code data
ret.qr = ret.text[0].text;
// Convert to QR-specific node when typecode matches
if (element.getAttribute('typecode') === 'QR') {
delete ret.text; // Remove standard text property
ret.nodeName = 'QR'; // Signal PDFMake to render as QR
ret.style = (ret.style || []).concat('html-qr');
}
}
return ret;
}
});
This example leverages this.applyStyle() to process ancestor CSS, then repurposes the text content as ret.qr—a special PDFMake property for QR codes—while changing the nodeName to ensure proper rendering.
Using customTag in Node.js
Implement the callback in a server-side script to handle custom badge elements:
const fs = require('fs');
const htmlToPdfmake = require('html-to-pdfmake');
const html = fs.readFileSync('sample.html', 'utf8');
const pdfDef = htmlToPdfmake(html, {
customTag: ({ element, ret }) => {
// Convert <badge> elements into styled text fragments
if (element.nodeName === 'BADGE') {
ret.text = element.textContent.trim();
ret.style = ['badge'];
ret.color = element.getAttribute('color') || 'blue';
}
return ret;
}
});
The same customTag approach functions identically in both browser and Node.js environments, requiring only that you provide the function within the options object passed to the converter.
When to Use customTag
Implement the customTag function when you need to:
- Support non-standard HTML tags such as web components (
<my-widget>,<user-card>) or framework-specific markup that the library does not natively recognize. - Extend existing standard tags with specialized behavior, such as converting
<code>blocks into QR codes or barcodes based on attribute flags. - Inject PDFMake-specific properties that have no HTML equivalent, including
qr,canvas,svg, or advanced layout configurations. - Modify node styling dynamically based on ancestor context or custom data attributes before the parser finalizes the node definition.
Summary
- The
customTagcallback inaymkdn/html-to-pdfmakehandles HTML tags without native converters, defined inindex.jsat lines 88-91. - It receives an object containing
element(DOM node),parents(ancestor array), andret(current PDFMake node), and must return the modifiedretobject. - The callback executes after generic processing but before final style reduction, allowing you to modify base properties or replace the node entirely.
- You can access parser methods like
this.applyStyle()through the bound context to resolve inherited CSS before applying custom logic. - Use cases include QR code generation, custom web component support, and injecting PDFMake-specific attributes unavailable in standard HTML.
Frequently Asked Questions
What parameters does the customTag function receive?
The function receives a single object with three properties: element (the raw DOM element with properties like nodeName and textContent), parents (an array of ancestor elements for context and style inheritance), and ret (the PDFMake node object generated so far). You must return the ret object to continue processing.
Can I use customTag to modify existing standard HTML tags?
Yes. While customTag primarily handles tags without native handlers, it executes for all elements after their initial processing. You can intercept standard tags like <p> or <code> to modify their ret properties, add PDFMake-specific attributes, or completely replace their output structure based on custom logic.
How do I access the parser instance methods inside customTag?
The library calls customTag using .call(this, params), binding the function to the parser instance. This binding allows you to access internal methods such as this.applyStyle({ ret, parents }) to resolve inherited CSS styles before applying your custom transformations, as shown in the QR code example from the README.
Does customTag work in both browser and Node.js environments?
Yes. The customTag option functions identically regardless of environment. Whether running in a browser with bundled JavaScript or in a Node.js script using require('html-to-pdfmake'), you simply pass the function within the options object. The only requirement is that the HTML string provided to htmlToPdfmake() is valid and parseable in your target environment.
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 →