Skip to content

Conversation

@nicolasiscoding
Copy link
Member

Summary

Fixes #160 - Missing bottom and right borders in table cells when using borderOptions configuration.

Problem

When converting HTML tables to DOCX with borderOptions specified, bottom and right borders were missing from table cells. Only top and left borders were being rendered.

Root Causes

  1. buildTableCellBorders() function bug: The function was using the wrong variable reference after destructuring, causing border properties to be lost during iteration.

  2. buildTableCell() edge-only border application: Table-level borders were only being applied to edge cells (first/last row/column), leaving middle cells without any borders.

Solution

Changes Made

  1. Fixed buildTableCellBorders() (lines 1766, 1769):

    • Changed to use destructured borders variable instead of original tableCellBorder object
    • This matches the pattern already used in buildTableBorders()
  2. Fixed buildTableCell() (lines 2572-2594):

    • Modified to apply table-level borders to ALL cells, not just edge cells
    • This ensures complete grid rendering when borderOptions is specified

Test Coverage

Added comprehensive test suite with 11 tests in tests/table-cell-borders.test.js:

  • ✅ Basic border rendering with borderOptions
  • ✅ All four borders (top, bottom, left, right)
  • ✅ Different stroke styles (dashed, dotted, double, single)
  • ✅ Custom colors
  • ✅ Complex tables (multi-row, with headers)
  • ✅ Edge cases (single cell, hidden borders)

Testing

Before Fix

  • 10/11 tests failing
  • Bottom and right borders missing in generated XML

After Fix

  • All 341 tests passing (11 new + 330 existing)
  • Bottom and right borders correctly present in all cells

Development Approach

This fix was implemented using Test-Driven Development (TDD):

  1. RED: Wrote failing tests demonstrating the bug
  2. GREEN: Implemented minimal fix to make tests pass
  3. REFACTOR: Cleaned up code while keeping tests green

Example

Before Fix:

<w:tcBorders>
  <w:top w:val="single" w:sz="1" w:space="0" w:color="000000"/>
  <w:left w:val="single" w:sz="1" w:space="0" w:color="000000"/>
</w:tcBorders>

After Fix:

<w:tcBorders>
  <w:top w:val="single" w:sz="1" w:space="0" w:color="000000"/>
  <w:bottom w:val="single" w:sz="1" w:space="0" w:color="000000"/>
  <w:left w:val="single" w:sz="1" w:space="0" w:color="000000"/>
  <w:right w:val="single" w:sz="1" w:space="0" w:color="000000"/>
</w:tcBorders>

Checklist

  • Tests added and passing
  • No regressions (all existing tests pass)
  • Code follows existing patterns
  • Issue linked and will auto-close on merge

This fix addresses the bug where table cell bottom and right borders
were not rendering when using borderOptions configuration.

Root Causes Fixed:
1. buildTableCellBorders() was using the wrong variable reference after
   destructuring, causing border properties to be lost
2. buildTableCell() was only applying table-level borders to edge cells,
   leaving middle cells without borders

Changes:
- Fixed buildTableCellBorders() to use destructured 'borders' variable
  instead of original 'tableCellBorder' object (lines 1766, 1769)
- Modified buildTableCell() to apply table-level borders to ALL cells,
  not just edge cells (lines 2572-2594)
- Added comprehensive test suite with 11 tests covering various border
  scenarios (tests/table-cell-borders.test.js)

All 341 tests pass, including 11 new regression tests for this issue.

Fixes #160

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
@nicolasiscoding nicolasiscoding linked an issue Dec 31, 2025 that may be closed by this pull request
@github-actions
Copy link

github-actions bot commented Dec 31, 2025

TurboDocx DOCX Diff Report

Automated HTML to DOCX regression testing | Powered by TurboDocx

Summary

  • ✅ Identical files: 67
  • 🔄 Changed files: 1
  • ➕ New files: 0
  • ➖ Deleted files: 0

⚠️ Changes Requiring Manual Review

word/document.xml

  • Type: content_change
  • Description: New paragraphs or content added - verify test case changes

📝 Detailed Changes

word/document.xml

  • Category: content_change
  • Severity: warn
  • Description: New paragraphs or content added - verify test case changes

🔍 OOXML Content Diff

Expand each section to see the actual OOXML changes

word/document.xml - New paragraphs or content added - verify test case changes
  <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
  <w:document xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" xmlns:cdr="http://schemas.openxmlformats.org/drawingml/2006/chartDrawing" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:pic="http://schemas.openxmlformats.org/drawingml/2006/picture" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:ve="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:vt="http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" xmlns:wne="http://schemas.microsoft.com/office/word/2006/wordml">
    <w:body>
  ...
+               <w:bottom w:val="single" w:sz="8" w:space="0" w:color="000000"/>
                <w:right w:val="single" w:sz="8" w:space="0" w:color="000000"/>
-               <w:bottom w:val="single" w:sz="8" w:space="0" w:color="000000"/>
  ...
+               <w:bottom w:val="single" w:sz="8" w:space="0" w:color="000000"/>
                <w:right w:val="single" w:sz="8" w:space="0" w:color="000000"/>
-               <w:bottom w:val="single" w:sz="8" w:space="0" w:color="000000"/>
  ...
+               <w:bottom w:val="single" w:sz="8" w:space="0" w:color="000000"/>
                <w:right w:val="single" w:sz="8" w:space="0" w:color="000000"/>
-               <w:bottom w:val="single" w:sz="8" w:space="0" w:color="000000"/>
  ...
+               <w:bottom w:val="single" w:sz="8" w:space="0" w:color="000000"/>
                <w:right w:val="single" w:sz="8" w:space="0" w:color="000000"/>
-               <w:bottom w:val="single" w:sz="8" w:space="0" w:color="000000"/>
  ...
+               <w:bottom w:val="single" w:sz="8" w:space="0" w:color="000000"/>
                <w:right w:val="single" w:sz="8" w:space="0" w:color="000000"/>
-               <w:bottom w:val="single" w:sz="8" w:space="0" w:color="000000"/>
  ...
+               <w:bottom w:val="single" w:sz="8" w:space="0" w:color="000000"/>
                <w:right w:val="single" w:sz="8" w:space="0" w:color="000000"/>
-               <w:bottom w:val="single" w:sz="8" w:space="0" w:color="000000"/>
  ...
+               <w:bottom w:val="single" w:sz="24" w:space="0" w:color="FFA500"/>
                <w:left w:val="single" w:sz="8" w:space="0" w:color="000000"/>
+               <w:right w:val="single" w:sz="16" w:space="0" w:color="A52A2A"/>
  ...
+               <w:bottom w:val="single" w:sz="24" w:space="0" w:color="FFA500"/>
  ...
+               <w:top w:val="single" w:sz="16" w:space="0" w:color="FFFF00"/>
                <w:bottom w:val="single" w:sz="24" w:space="0" w:color="FFA500"/>
                <w:left w:val="single" w:sz="8" w:space="0" w:color="000000"/>
+               <w:right w:val="single" w:sz="16" w:space="0" w:color="A52A2A"/>
  ...
+               <w:top w:val="single" w:sz="16" w:space="0" w:color="FFFF00"/>
  ...
+               <w:bottom w:val="single" w:sz="8" w:space="0" w:color="000000"/>
                <w:right w:val="single" w:sz="8" w:space="0" w:color="000000"/>
-               <w:bottom w:val="single" w:sz="8" w:space="0" w:color="000000"/>
  ...
+               <w:bottom w:val="single" w:sz="8" w:space="0" w:color="000000"/>
                <w:right w:val="single" w:sz="8" w:space="0" w:color="000000"/>
-               <w:bottom w:val="single" w:sz="8" w:space="0" w:color="000000"/>
  ...
+               <w:bottom w:val="single" w:sz="8" w:space="0" w:color="000000"/>

... [Diff truncated - download artifact for full diff]

🚀 Powered by TurboDocx | html-to-docx

Automated DOCX regression testing • Catch document generation bugs before they ship • 100% open source

Generated by TurboDocx DOCX Diff workflow • Learn more

Added dedicated test that uses the exact code example from the issue
reporter (dt-eric-lefevreardant) to verify both bottom and right borders
are now correctly rendered.

This test explicitly verifies the XML output matches what was expected
in the original bug report.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
@nicolasiscoding nicolasiscoding marked this pull request as ready for review January 2, 2026 18:41
Co-authored-by: Eric Lefevre-Ardant <134555809+dt-eric-lefevreardant@users.noreply.github.com>
@nicolasiscoding
Copy link
Member Author

@AmitSharma512

@K-Kumar-01
Copy link
Collaborator

@nicolasiscoding

<table style="border-collapse: collapse; width: 100%; border-width: 1px; border-style: hidden; height: 76px;" border="1">
    <colgroup>
        <col style="width: 25.0399%;">
        <col style="width: 25.0399%;">
        <col style="width: 25.0399%;">
        <col style="width: 25.0399%;">
    </colgroup>
    <tbody>
        <tr style="height: 19px;">
            <td style="height: 19px;">1,1</td>
            <td style="height: 19px;">1,2</td>
            <td style="height: 19px;">1,3</td>
            <td style="height: 19px;">1,4</td>
        </tr>
        <tr style="height: 19px;">
            <td style="height: 19px;">2,1</td>
            <td style="height: 19px;">2,2</td>
            <td style="height: 19px;">2,3</td>
            <td style="height: 19px;">2,4</td>
        </tr>
        <tr style="height: 19px;">
            <td style="height: 19px;">3,1</td>
            <td style="height: 19px;">3,2</td>
            <td style="height: 19px;">3,3</td>
            <td style="height: 19px;">3,4</td>
        </tr>
        <tr style="height: 19px;">
            <td style="height: 19px;">4,1</td>
            <td style="height: 19px;">4,2</td>
            <td style="height: 19px;">&nbsp;4,3</td>
            <td style="height: 19px;">4,4</td>
        </tr>
    </tbody>
</table>


<table style="border-collapse: collapse; border-left:1px solid black; border-right: 2px solid brown; border-top: 2px solid yellow; border-bottom: 4px solid orange">
    <tbody>
        <tr>
            <td>Row 1, Col 1</td>
            <td>Row 1, Col 2</td>
        </tr>
        <tr>
            <td>Row 2, Col 1</td>
            <td>Row 2, Col 2</td>
        </tr>
    </tbody>
</table>

Due to the changes, the rendering has changed for the above two tables, which is wrong.

Output

image image

Expected Output

image

Copy link
Collaborator

@K-Kumar-01 K-Kumar-01 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Breaking the existing functionality. Needs changes.

nicolasiscoding and others added 2 commits January 20, 2026 18:36
Fixes regression where tables with border-style: hidden or none
were incorrectly showing borders after the fix for issue #160.

Root Cause:
The fix for #160 applied table-level borders to all cells unconditionally,
which broke tables that explicitly set border-style: hidden or none.

Changes:
- Add conditional checks before applying table borders to cells
- Only apply borders if border-style is not 'hidden' or 'none'
- Preserves the #160 fix for borderOptions while respecting CSS border-style
- Add regression tests for border-style: hidden and table-level border colors

Testing:
- All 343 tests pass including new regression tests
- Verified border-style: hidden suppresses borders correctly
- Verified table-level colored borders are respected
- Original #160 fix remains intact (all cells get borders when appropriate)

Test cases added:
1. Table with border-style: hidden (Kushal's first example)
2. Table with table-level colored borders (Kushal's second example)

Reported-by: K-Kumar-01 <https://github.com/K-Kumar-01>

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Add 7 new unit tests ported from manual examples in example-node.js,
covering edge cases and complex border scenarios:

Tests added:
1. Basic table without borders or styles
2. border-style: none with border attribute (conflicting directives)
3. Normal table with border attribute
4. border-width: 0px with border-style: solid
5. Complex border styles with multiple colors
6. Table with border attribute and border-collapse
7. Table with rowspan and colspan

All 350 tests pass. These tests provide better coverage of real-world
table border scenarios found in the manual test suite.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bottom border missing in table

5 participants