# How to Debug html-to-pdfmake Conversion Issues: A Complete Troubleshooting Guide

> Debug html-to-pdfmake conversion issues effectively. Inspect DOM, verify options, and trace parsing with this complete troubleshooting guide for seamless PDF generation from HTML.

- Repository: [Aymeric/html-to-pdfmake](https://github.com/aymkdn/html-to-pdfmake)
- Tags: how-to-guide
- Published: 2026-02-26

---

**To debug html-to-pdfmake conversion issues, inspect the parsed DOM before conversion, verify your options object, and trace the recursive walk through `parseElement` while checking style aggregation in `applyStyle` and `parseStyle`.**

The `html-to-pdfmake` library transforms HTML strings into pdfmake document definitions, but when the output doesn't match expectations, debugging requires understanding the three-phase conversion pipeline in [`index.js`](https://github.com/aymkdn/html-to-pdfmake/blob/main/index.js). Whether you're troubleshooting missing styles, broken tables, or disappearing images, this guide provides systematic steps to debug html-to-pdfmake conversion issues using the actual source code implementation.

---

## Verify Input HTML and DOM Parsing

The conversion begins by parsing your HTML string using the browser's native `DOMParser` (lines 21-31 in [`index.js`](https://github.com/aymkdn/html-to-pdfmake/blob/main/index.js)). Errors here propagate silently or produce unexpected node structures.

### Check for Malformed HTML

Stray whitespace, unclosed tags, or HTML entities can cause the parser to insert unexpected nodes. Before calling `htmlToPdfMake`, test the parsed DOM directly:

```javascript
const html = '<div style="display:none">Hidden</div><p>  spaced  text </p>';
const parser = new DOMParser();
const doc = parser.parseFromString(html, 'text/html');
console.log(doc.body.innerHTML); // Inspect the normalized structure

```

### Verify Hidden Elements and Whitespace Handling

Two options control initial filtering:

- **`showHidden`**: Set to `true` to include elements with `display:none` (default is `false`)
- **`removeExtraBlanks`**: Set to `false` to preserve whitespace in `<pre>` or `<code>` blocks

```javascript
const htmlToPdfMake = require('html-to-pdfmake');
const doc = htmlToPdfMake(html, {
  showHidden: true,
  removeExtraBlanks: false
});

```

---

## Inspect the Options Object

The options object (lines 13-20) directly influences how `parseElement` and `applyStyle` behave. Misconfiguration here is a common source of silent failures.

### Default Styles Override

The `defaultStyles` option merges with the built-in style map (lines 58-79). Setting a key to `null` removes that style entirely, but forgetting to spread existing defaults can wipe unintended styles:

```javascript
// Removes bold styling from <b> tags only
const doc = htmlToPdfMake('<b>no bold</b>', {
  defaultStyles: { b: null }
});

```

### Table Auto-Sizing Pitfalls

When `tableAutoSize` is `true`, the library calculates column widths from `width` attributes or percentage-based CSS. If the `<table>` lacks a `width="100%"` attribute, the auto-sizing logic may skip percentage calculations (line 194).

```javascript
const html = `
<table width="100%">
  <tr><td style="width:30%">A</td><td style="width:70%">B</td></tr>
</table>`;
const doc = htmlToPdfMake(html, { tableAutoSize: true });

```

### Image Reference Mode

With `imagesByReference: true`, the function returns an object `{content, images}` instead of a direct document definition. Forgetting to access `result.images` leads to missing images in the final PDF (lines 166-171).

```javascript
const result = htmlToPdfMake('<img src="logo.png">', {
  imagesByReference: true
});
console.log(result.images); // Check the generated reference keys

```

### Custom Tag Handler Errors

The `customTag` callback receives `{element, parents, ret}` but errors inside this function are silently caught. Add defensive logging:

```javascript
const doc = htmlToPdfMake('<my-box></my-box>', {
  customTag: ({element, parents, ret}) => {
    try {
      if (element.tagName === 'MY-BOX') {
        return {
          canvas: [{ type: 'rect', x: 0, y: 0, w: 200, h: 50 }],
          margin: [0, 10, 0, 10]
        };
      }
    } catch (e) {
      console.error('Custom tag error:', e);
    }
    return ret;
  }
});

```

---

## Trace the Recursive Element Walker

The core conversion logic resides in `parseElement` (lines 41-95), which recursively processes each DOM node. Understanding this walk helps diagnose structural issues.

### Stack vs Text Detection

The `searchForStack` function (lines 37-44) determines whether a node should become a `stack` (container) or `text` node. Block-level elements like `<div>` or `<p>` trigger stack mode, while inline elements remain text.

If elements appear concatenated on a single line when they should stack vertically, check that the parent container is recognized as a block element:

```javascript
// Debug the node type detection
const html = '<div><p>Line 1</p><p>Line 2</p></div>';
const doc = htmlToPdfMake(html);
console.log(JSON.stringify(doc, null, 2));
// Should show nested stacks, not flat text array

```

### Temporary Debug Logging

Insert a temporary log at the top of `parseElement` to trace the traversal:

```javascript
// Inside node_modules/html-to-pdfmake/index.js, temporarily add:
if (element.nodeName) {
  console.log('Parsing', element.nodeName, 
              'parent chain:', parents.map(p => p.nodeName));
}

```

This reveals the exact path taken through the DOM and helps identify where the walker diverges from expectations.

---

## Debug Style Aggregation

Styles flow through three layers: default styles (lines 58-79), inline `style` attributes, and CSS classes. The `applyStyle` (lines 55-90) and `parseStyle` (lines 68-112) functions handle this transformation.

### CSS-to-pdfmake Property Mapping

Not all CSS properties map directly to pdfmake. Key mappings include:

- `background-color` → `fillColor` (for table cells)
- `text-decoration: underline` → `decoration: 'underline'`
- `font-weight: bold` → `bold: true`
- Margins/paddings → arrays `[left, top, right, bottom]` in points

### Common Style Bugs

**RGBA Opacity Dropped**: When using `rgba()` colors with alpha < 1, the opacity is lost unless `fillOpacity` is explicitly set. Use solid hex colors (`#ff0000`) for reliable rendering.

**Margin Auto Ignored**: The parser silently drops `margin: auto` (line 334 in `parseStyle`). Always specify concrete units:

```javascript
// Bad
<div style="margin: auto">

// Good
<div style="margin: 20pt">

```

**Inherited Underlines**: Text decoration properties inherit differently than other styles. If a parent `<div>` has `text-decoration: underline`, child text nodes may inherit this unexpectedly depending on the `removeTagClasses` setting.

### Inspecting Computed Styles

Always serialize the final document definition to verify style transformation:

```javascript
const doc = htmlToPdfMake('<p style="margin:2cm;color:#0f0">Test</p>');
console.log(JSON.stringify(doc, null, 2));
// Expected output shows margin converted to points: [56.6929,56.6929,56.6929,56.6929]
// And color normalized to: "#00ff00"

```

---

## Troubleshoot Table Rendering

Tables undergo complex post-processing for column spans, row spans, and width calculations (lines 95-99, 115-130).

### Colspan and Rowspan Handling

The library processes `colspan` and `rowspan` attributes during the stack-building phase (lines 135-147). If cells appear misaligned or missing:

1. Verify that `colSpan` and `rowSpan` are lowercase in your HTML (the parser checks these attributes specifically)
2. Ensure table rows (`<tr>`) are direct children of `<table>`, not wrapped in intermediate `<tbody>` tags that might confuse the walker

### Table Auto-Sizing Logic

When `tableAutoSize: true`, the library extracts widths from:
- `width` attributes on `<table>` and `<col>` elements
- Percentage values in `style="width:X%"`

Critical requirement: The `<table>` must have `width="100%"` attribute for percentage-based column widths to calculate correctly (line 194). Without this, the library cannot determine the relative proportions.

### Data Attributes for Advanced Control

Use `data-pdfmake` to inject raw pdfmake properties:

```javascript
const html = `
<table data-pdfmake='{"layout":"noBorders","dontBreakRows":true}' width="100%">
  <tr><th colspan="2">Header</th></tr>
  <tr><td rowspan="2">A</td><td>B</td></tr>
  <tr><td>C</td></tr>
</table>`;

const docDef = htmlToPdfMake(html, {tableAutoSize:true});
console.log(JSON.stringify(docDef.table.layout)); // "noBorders"

```

If `data-pdfmake` JSON is malformed, the library logs to `console.error` but continues processing, potentially ignoring your custom settings.

---

## Verify Image Handling

Images support two processing modes controlled by the `imagesByReference` option (lines 166-171).

### Embedded vs Reference Mode

**Embedded mode** (default): Returns image nodes with `src` containing data URLs or file paths directly in the content tree.

**Reference mode** (`imagesByReference: true`): Returns an object with `content` and `images` properties. Image URLs are replaced with reference keys (`img_ref_<suffix><index>`) and the actual data is stored in the `images` map.

### Debugging Image Paths

When images appear missing in the final PDF:

1. **Check the return structure**: If using `imagesByReference: true`, ensure you're accessing `result.images`, not just `result` or `result.content`.

```javascript
const result = htmlToPdfMake('<img src="logo.png">', {
  imagesByReference: true
});

// Correct way to inspect
console.log('Content:', result.content);
console.log('Images map:', result.images); 
// { img_ref_xxxxxx0: 'data:image/png;base64,...' }

```

2. **Verify URL accessibility**: The library handles both data URLs and relative paths, but the final PDF generation (performed by pdfmake, not html-to-pdfmake) requires that image URLs be resolvable in the target environment (Node.js filesystem or browser blob URLs).

3. **Check for JSON string wrapping**: The parser handles cases where `src` attributes contain JSON-encoded strings, but verify your HTML doesn't contain double-encoded entities.

---

## Summary

- **Start with the input**: Verify your HTML parses correctly in a browser's `DOMParser` and check that `showHidden` and `removeExtraBlanks` options match your content needs.
- **Audit the options**: Misconfigured `defaultStyles`, `tableAutoSize`, or `imagesByReference` settings are common culprits for missing formatting or content.
- **Trace the recursion**: Add temporary logging inside `parseElement` to follow the DOM traversal and verify that `searchForStack` correctly identifies block-level containers.
- **Inspect style aggregation**: Use `JSON.stringify` on the output to verify that `applyStyle` and `parseStyle` correctly transformed CSS properties like margins, colors, and decorations.
- **Validate tables and images**: Ensure tables have proper `width` attributes for auto-sizing and that image references are correctly extracted when using `imagesByReference` mode.

---

## Frequently Asked Questions

### Why are my CSS styles not appearing in the PDF output?

Styles flow through `applyStyle` and `parseStyle` in [`index.js`](https://github.com/aymkdn/html-to-pdfmake/blob/main/index.js), which map CSS properties to pdfmake equivalents. If styles are missing, verify that you haven't set `removeTagClasses: true` (which removes the auto-generated `html-tag` classes that carry custom CSS), check that `ignoreStyles` doesn't include your property, and ensure you're using supported units (px, pt, cm, rem) rather than `auto` or unsupported CSS variables.

### How do I fix tables that render with incorrect column widths?

Tables require explicit width handling in html-to-pdfmake. First, ensure `tableAutoSize: true` is set in your options. Then verify that your `<table>` tag includes a `width="100%"` attribute (line 194 in [`index.js`](https://github.com/aymkdn/html-to-pdfmake/blob/main/index.js)), as percentage-based column widths cannot calculate without this reference. For complex layouts, use `<colgroup>` with `<col width="X%">` elements placed before any `<tr>` rows, or inject raw pdfmake properties via `data-pdfmake='{"widths":["*","auto"]}'`.

### Why are images missing from my generated PDF?

Images disappear when the reference map isn't properly handled or when URLs are inaccessible. If using `imagesByReference: true`, remember that the function returns `{content, images}` rather than a direct document definition—you must merge `result.images` into your pdfmake definition's `images` property. For embedded mode, verify that `src` attributes contain valid data URLs or resolvable paths, and check the browser console for CORS errors or 404s when loading external images.

### How can I debug custom tag handlers that aren't working?

The `customTag` callback receives `{element, parents, ret}` but errors inside this function are silently swallowed by the library's error handling. To debug, wrap your custom logic in a `try/catch` block with explicit `console.error` logging. Also verify that `removeTagClasses` isn't `true`, as this removes the `html-tag` classes that your handler might rely on for element identification. Test with simple HTML first, then gradually add complexity to isolate the failure point.