How to Resolve Styling Conflicts in html-to-pdfmake

You resolve styling conflicts in html-to-pdfmake by leveraging its last-wins merging hierarchy—where default tag styles apply first, inline CSS overrides them, and constructor options like ignoreStyles, removeTagClasses, and defaultStyles take final precedence.

Converting HTML to PDFMake definitions often produces unexpected visual results when multiple style sources collide. The html-to-pdfmake library merges built-in defaults, inline CSS, and user-provided options in a specific order defined in index.js. Understanding this resolution pipeline allows you to suppress unwanted properties and ensure your PDF output matches your design specifications exactly.

Understanding the Style Merging Hierarchy

The library processes three distinct style sources during conversion, as implemented in the constructor and parsing logic of index.js:

  1. Built-in default styles – Defined in lines 58-78, these map HTML tags to PDFMake properties (e.g., <b> maps to {bold: true}).
  2. Inline CSS attributes – Parsed by the parseStyle function around line 768, converting attributes like style="margin:10px" into PDFMake-compatible keys.
  3. User-provided override options – Constructor parameters including defaultStyles, ignoreStyles, and removeTagClasses (stored in lines 49-51).

When the same property exists in multiple sources, html-to-pdfmake follows a last-wins rule. The default style applies first, inline CSS overrides it, and option overrides take final precedence. The ignoreStyles array removes properties entirely before merging, preventing them from appearing regardless of their source.

Configuration Options for Conflict Resolution

Several constructor options control how styles merge:

  • ignoreStyles – An array of CSS properties to exclude from parsing (e.g., ['margin', 'padding']).
  • removeTagClasses – Boolean flag (line 49) that disables automatic html-TAG class generation on every node.
  • defaultStyles – Object that replaces or extends the built-in mappings for specific tags.
  • tableAutoSize – Boolean (line 45) that prioritizes explicit width/height values on table cells over calculated defaults.
  • showHidden – Boolean (line 48) that includes elements with display:none in the output.
  • removeExtraBlanks – Boolean (line 48) that aggressively trims whitespace when white-space:pre conflicts with PDFMake defaults.

Common Styling Conflicts and Solutions

Inline Margins vs. Default Tag Margins

Paragraphs and headers carry default margins in defaultStyles, but inline style="margin:20px" declarations may produce unexpected spacing. Since the default applies first and inline styles override selectively, you might inherit unwanted margin components.

Resolution: Use ignoreStyles: ['margin'] to strip all CSS margin declarations, forcing reliance on defaultStyles definitions. Alternatively, override the baseline entirely by providing defaultStyles.p.margin in your options.

Table Border Duplication

Table headers (<th>) receive default borders via defaultStyles.th, while inline style="border:1px solid red" attempts to modify them. Without intervention, these properties may compound rather than replace.

Resolution: Supply an empty string or null for the specific property in defaultStyles.th.border to remove the baseline before the inline style applies.

Text Decoration Collisions

Both default conversion (e.g., <u>decoration: 'underline') and inline text-decoration properties populate the decoration array. Duplicate values create unwanted visual artifacts.

Resolution: The applyStyle function (lines 84-92 in index.js) automatically deduplicates decorations. Ensure you do not manually inject duplicate values through custom styles.

Unwanted html-TAG Classes

By default, every element receives a class like html-p or html-div, which can conflict with downstream CSS processing of the generated JSON.

Resolution: Set removeTagClasses: true in the constructor options to suppress automatic class generation (as stored in line 49).

Table Cell Dimension Conflicts

Explicit widths set via style="width:250px" may be ignored if defaultStyles.th or defaultStyles.td specify different dimensions.

Resolution: Enable tableAutoSize: true to prioritize explicit CSS dimensions over internal calculations.

Whitespace Handling Conflicts

Inline white-space:pre preserves spacing that PDFMake's default parser may trim, resulting in layout shifts.

Resolution: Activate removeExtraBlanks: true to force aggressive whitespace normalization, though this incurs a performance cost.

The Style Resolution Algorithm

The core merging logic resides in the applyStyle function around line 655 of index.js. The algorithm executes these steps in sequence:

  1. Collect CSS classes – Gathers classes from the element, including the auto-generated html-TAG class unless removeTagClasses is enabled.
  2. Apply default styles – Retrieves tag-specific defaults from the internal mapping.
  3. Parse inline CSS – Processes the style attribute via parseStyle, converting CSS to PDFMake properties.
  4. Filter ignored properties – Skips any keys listed in the ignoreStyles array.
  5. Deduplicate decorations – Merges underline and line-through values into a unique array.
  6. Normalize margins – Converts CSS margin shorthand into PDFMake's left-top-right-bottom object format.
  7. Return merged object – Produces the final ret object containing resolved styles for the PDFMake document definition.

Practical Code Examples

The following examples demonstrate resolving specific conflicts using the options discussed.

Suppressing Default Margins and Tag Classes

const opts = {
  window,                         // Required in Node.js environments
  removeTagClasses: true,        // Disable html-p, html-div classes
  ignoreStyles: ['margin']       // Ignore CSS margins, use defaults only
};

const html = '<p style="margin:20px; color:red">Hello</p>';
const pdfDef = htmlToPdfmake(html, opts);
// Result: The node contains only color:'#ff0000'; margin comes from defaultStyles.p

Overriding Default Table Header Styles

const opts = {
  window,
  defaultStyles: {
    th: { 
      fillColor: ''  // Remove default gray background
    }
  }
};

const pdfDef = htmlToPdfmake('<table><tr><th>Header</th></tr></table>', opts);
// Result: Header cell appears without the default fillColor:'#EEEEEE'

Preserving Hidden Elements and Explicit Widths

const opts = {
  window,
  showHidden: true,      // Include display:none elements
  tableAutoSize: true    // Respect explicit width/height values
};

const html = `
  <div style="display:none">Secret Content</div>
  <table style="width:100%">
    <tr>
      <td style="width:250px">Fixed Width</td>
      <td>Auto Width</td>
    </tr>
  </table>
`;

const pdfDef = htmlToPdfmake(html, opts);
// Result: Secret Content appears in PDF; first cell respects 250px width

Summary

  • html-to-pdfmake resolves styling conflicts using a last-wins hierarchy: default styles apply first, inline CSS overrides them, and constructor options take final precedence.
  • Use ignoreStyles to prevent specific CSS properties from being parsed, and removeTagClasses to eliminate automatic html-TAG classes.
  • Override built-in defaults by providing custom objects to the defaultStyles option.
  • Enable tableAutoSize to ensure explicit table dimensions override internal calculations, and showHidden to retain elements with display:none.
  • The merging logic is centralized in the applyStyle function (around line 655) of index.js, with default style definitions located in lines 58-78.

Frequently Asked Questions

Why does my inline style get ignored when converting HTML to PDFMake?

Your inline style likely conflicts with a hardcoded default in defaultStyles or is being filtered by the ignoreStyles array. According to the source code in index.js (lines 58-78), tags like <p> and <th> carry predefined margins and borders that override or merge with your CSS. Check that you have not included the property in ignoreStyles, and verify that tableAutoSize is enabled if working with table dimensions.

How do I remove the default gray background from table headers?

The library assigns fillColor:'#EEEEEE' to <th> elements by default. To remove this, pass a defaultStyles object in your constructor options that sets th.fillColor to an empty string or null. This empty value clears the default before inline styles are processed, allowing complete control over the header appearance.

Can I prevent html-to-pdfmake from adding html-p classes to every element?

Yes. Set removeTagClasses: true in your options object. By default, the constructor (line 49 of index.js) generates classes like html-p and html-div for every node to aid styling, but this flag disables that behavior entirely, preventing conflicts with your own class-based logic.

What is the performance impact of using removeExtraBlanks to fix whitespace issues?

The removeExtraBlanks option (line 48) forces aggressive whitespace cleanup across the entire document, which requires additional string processing and node traversal. While effective for resolving conflicts between white-space:pre and PDFMake's default trimming, you should only enable it when necessary for layout accuracy, as it increases conversion time for large documents.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →