3

I need to render an invoice PDF with puppeteer that contains a table with items. These items can contain description/comments/etc. The table overflows onto the next div beneath it. In case it overflows the behaviour should break into the next page.

I've tried many css break-* and @page with no luck, max height but then the table isn't fully visible and many other things. Should I jump ship of the table and just use divs?

.pdf {
  background-color: #FFF;
  overflow: hidden !important;
  display: grid;
  grid-template-rows: 190px minmax(10px, 246px) 786px 212px 1fr;
  grid-row-gap: 1em;
}

.table-container {
  table { page-break-inside: auto }
  tr    { page-break-inside: avoid; page-break-after: auto }
  thead { display: table-header-group }
  tfoot { display: table-footer-group }
}

table {
  width: 100%;
  border-spacing: 0;
  border-collapse: collapse;
}

// ... other elms ...
<div class="pdf">
    <header>
        ... company header logo and other details ...
    </header>
    <div class="details">
        ... invoice details ...
    </div>
    <div class="table-container">
        <table>
            <thead>
            <tr>
                <th class="text-left">PRODUCT</th>
                <th class="text-left">DESCRIPTION</th>
                <th class="text-right">PRICE</th>
                <th class="text-right">UNIT</th>
                <th class="text-right">QUANTITY</th>
                <th class="text-right">TOTAL</th>
            </tr>
            </thead>
            <tbody>
                <tr></tr>
            </tbody>
        </table>
    </div>
    <div class="details">
        this div gets overflowed
    </div>
</div>
Katch
  • 170
  • 1
  • 20

1 Answers1

0

Try like this:

.pdf {
  background-color: #FFF;
  overflow: hidden !important;
  display: grid;
  grid-template-rows: 190px minmax(10px, 246px) auto 212px 1fr;
  grid-row-gap: 1em;
}

table {
  width: 100%;
  border-spacing: 0;
  border-collapse: collapse;
  min-height: 786px;
}

@media print {
  .table-container table {
      page-break-inside: auto;
  }
  .table-container tr {
    page-break-inside: avoid;
    page-break-after: auto;
  }
  .table-container thead {
    display: table-header-group;
  }
  .table-container tfoot {
    display: table-footer-group;
  }
}
<div class="pdf">
  <header>
    ... company header logo and other details ...
  </header>
  <div class="details">
    ... invoice details ...
  </div>
  <div class="table-container">
    <table>
      <thead>
        <tr>
          <th class="text-left">PRODUCT</th>
          <th class="text-left">DESCRIPTION</th>
          <th class="text-right">PRICE</th>
          <th class="text-right">UNIT</th>
          <th class="text-right">QUANTITY</th>
          <th class="text-right">TOTAL</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
        </tr>
        <tr>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
        </tr>
        <tr>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
        </tr>
        <tr>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
        </tr>
        <tr>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
        </tr>
        <tr>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
        </tr>
        <tr>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
        </tr>
        <tr>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
        </tr>
        <tr>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
        </tr>
        <tr>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
        </tr>
        <tr>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
        </tr>
        <tr>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
        </tr>
        <tr>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
        </tr>
        <tr>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
        </tr>
        <tr>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
        </tr>
        <tr>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
        </tr>
        <tr>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
        </tr>
        <tr>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
        </tr>
        <tr>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
        </tr>
        <tr>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
        </tr>
        <tr>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
        </tr>
        <tr>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
        </tr>
        <tr>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
        </tr>
        <tr>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
        </tr>
        <tr>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
        </tr>
        <tr>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
        </tr>
        <tr>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
        </tr>
        <tr>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
        </tr>
        <tr>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
        </tr>
        <tr>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
        </tr>
        <tr>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
        </tr>
        <tr>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
        </tr>
        <tr>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
        </tr>
        <tr>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
        </tr>
        <tr>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
        </tr>
        <tr>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
        </tr>
        <tr>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
        </tr>
        <tr>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
        </tr>
        <tr>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
        </tr>
        <tr>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
        </tr>
        <tr>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
        </tr>
        <tr>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
          <td>test</td>
        </tr>
      </tbody>
    </table>
  </div>
  <div class="details">
    this div gets overflowed
  </div>
</div>

Changing the 3rd value in grid-template-rows to auto allows the 3rd row (.table-container) to have a height greater than 786px. This solves the overflow issue.

It appears that the grid layout is also messing with the table by causing the thead element to repeat over tbody content at the beginning of each repeating page. If it were me, I'd remove the display: grid, grid-template-rows and grid-row-gap rules, at least for printing, instead doing something like the below. It will be much less error-prone that way.

@media print {
   .pdf {
      display: block;
      grid-template-rows: none;
      grid-row-gap: 0;
   }

   .pdf > div {
      margin-bottom: 1em;
   }

   header {
      height: 190px;
   }

   header + .details {
      height: 246px;
      min-height: 10px;
      max-height: 246px;
   }

   .table-container {
      height: auto;
   }

   .table-container + .details {
      height: 212px;
   }

   /* further rules here... */
}
sbgib
  • 5,580
  • 3
  • 19
  • 26
  • The grid is actually how the view should look like. The table must have a fixed height. In case the items exceed this height it should overflow to the next page. – Katch Oct 27 '20 at 13:02
  • Ok, but when it does have a fixed height, it overflows on to the `div` that comes after. So in that case, you need to either remove content from the table (or make it smaller or hide it) so it fits your fixed height constraint, or you need to remove the fixed height constraint so that the table can be displayed. They're not really compatible. – sbgib Oct 28 '20 at 07:25
  • I've updated this answer to use a `min-height` on the table, so that it can have that fixed height and grow as needed, while still avoiding the other issues by not using grid layout specifically. If you give the code in the answer a try you should see that the way it looks has not changed. – sbgib Oct 30 '20 at 08:54