How to avoid page break inside table row for wkhtmltopdf

115,211

Solution 1

Update 17.09.2015: Check the version you are using: wkhtmltopdf 0.12.2.4 is said to fix the problem (I have not checked).


This is a known issue in wkhtmltopdf. The page breaking algorithm used by webkit (the WK in WKhtmltopdf) doesn't really work well for large tables. I suggest breaking the table down to smaller chunks that are more easily split to pages and using the css a lot:

table, tr, td, th, tbody, thead, tfoot {
    page-break-inside: avoid !important;
}

Also have a look at the following wkhtmltopdf issues, they have interesting comments that discuss for example the table splitting problem. There is a JS solution that programmatically splits tables in 168 that might help you (I don't use it though).

Update 08.11.2013 There is much discussion about this in issue 168 linked above. Someone has managed to compile a version of wkhtmltopdf that supports better table breaking, but unfortunately it seems that it's not officially released and might contain other bugs. I don't know how to get it and I don't know how to compile on Windows, but anyone interested can check for example the comment here (see new update below).

Update 24.02.2014 You will be pleased to hear that in wkhtmltopdf 0.12 this feature among others has been greatly improved. However, wait for 0.12.1 and test thoroughly before starting to use any new version, it's still a little unstable although the new guys working on with antialize are doing a Great job (ashkulz rocks)! Keep updated at wkhtmltopdf.org and github. The google code site is obsolete and being slowly migrate.

Solution 2

It is old post, but since i was wasting lot of time trying to find proper solution, i will put it here, maybe it will be useful to someone.

So from what i read, the problem with

page-break-inside: avoid

is that it doesn't work. But actually if you set it on element that has display:block it works as expected (as noted somewhere in SO). so for simple structure of table css with

td div, th div{
    page-break-inside: avoid;
}

and table structure

<table>
....
<tr>
    <td><div>some text</div></td>
    <td><div>more text</div></td>
</tr>
....
</table>

will work as expected.

I had bit more complicated case with rowspans, so the solution from above was breaking it to peaces, which wasn't desired effect. I solved it using divs for each rowspaned set of lines. My jquery js doing all the job:

$(window).load(function () {
    var sizes = {};
    $('#the_table tr:first th').each(function (a, td) {         
        var w = $(td).width();
        if (sizes.hasOwnProperty('' + a)) {
            if (sizes['' + a] < w)
                sizes['' + a] = w;
        }
        else {
            sizes['' + a] = w;
        }
    });

    var tableClone = $('#the_table').clone();
    $('#the_table').replaceWith('<div class="container"></div>');

    var curentDivTable;
    var cDiv = $('.container');
    tableClone.find('tr').each(function (i, ln) {
        var line = $(ln);
        if (line.hasClass('main_row')) {
            var div = $('<div class="new-section"><table><tbody>')
            currentDivTable = div.find('tbody');
            cDiv.append(div);               
        }
        currentDivTable.append(line);
    });
    //optional - maybe in % its better than px
    var sum = 0;
    $.each(sizes, function (a, b) {
        sum += b;
    });
    var widths = {};
    $.each(sizes, function (a, b) {
        var p = Math.ceil(b * 100 / sum);
        widths['' + a] = p + '%';
    });
    //setup
    $('.container table').each(function (a, tbl) {
        $(tbl).find('tr:first td, tr:first th').each(function (b, td) {
            $(td).width(widths['' + b]);
        });
        $(tbl).addClass('fixed');
    });
});

css:

div.new-section {
    page-break-inside: avoid;
}
.container, .new-section, .new-section table.fixed{
    width: 100%;
}

.new-section table.fixed{
    table-layout:fixed;
}

I don't know if everything is needed and I don't think its perfect, but it does the job. Tested on chrome only

Solution 3

Since 0.12 this issue has been solved but, sometimes, when a table is too long to fit in the page, wkhtmltopdf breaks it in two parts and repeats the column headers on the new page and these column headers appear superposed to the first row.

I found a temporal solution to this problem on the wkhtmltopdf github issues section: https://github.com/wkhtmltopdf/wkhtmltopdf/issues/2531

Just add this lines to your view css:

tr {
  page-break-inside: avoid; 
}

Solution 4

I've digged into this problems for days, and finally found the perfect solution. You can reference this project phpwkhtmltopdf. Look into the directory article and you will find 3 solutions for 3 problems. In short, the ultimate solution is add the css style

thead {
    display: table-row-group;
}
tr {
    page-break-before: always;
    page-break-after: always;
    page-break-inside: avoid;
}
table {
    word-wrap: break-word;
}
table td {
    word-break: break-all;
}

If you're Chinese, feel free to check this site关于wkhtmltopdf,你一定想知道这些 Check out the gist if you wish gist for wkhtmltopdf

Solution 5

In my particular case for some reason none of the previous answers worked for me. What ended up working was actually a combination of several things.

  1. I installed (in Ubuntu 16.04) the Wkhtmltopdf python wrapper called pdfkit using pip3, and then instead of installing Wkhtmltopdf via apt-get I installed the static binary (version 0.12.3) by following the script below, taken from here

    #!/bin/sh
    
    sudo apt-get install -y openssl build-essential xorg libssl-dev
    wget http://download.gna.org/wkhtmltopdf/0.12/0.12.3/wkhtmltox-0.12.3_linux-generic-amd64.tar.xz
    tar -xJf wkhtmltox-0.12.3_linux-generic-amd64.tar.xz
    cd wkhtmltox
    sudo chown root:root bin/wkhtmltopdf
    sudo cp -r * /usr/
    
  2. Added this CSS (as suggested in one of the answers here):

    tr, td div, th div{
        page-break-inside: avoid;
    }
    
  3. And then also add <thead> and <tbody> tags as suggested here as well (without these the table would still break in an ugly way):

    <table>
        <thead>
            <tr>
                <th>Column 1</th>
                <th>Column 2</th>
            </tr>
        </thead>
    
        <tbody>
            <tr>
                <td>Value 1</td>
                <td>Value 2</td>
            </tr>
        </tbody>
    </table>
    

With these modifications I can now successfully use Mako templates to generate the HTML and then feed that to Wkhtmltopdf and get a beautifully paginated PDF.

Share:
115,211
Mohammad Sadiq Shaikh
Author by

Mohammad Sadiq Shaikh

Software developer

Updated on October 27, 2021

Comments

  • Mohammad Sadiq Shaikh
    Mohammad Sadiq Shaikh over 2 years

    I am generating pdf report from html page with one table.

    I am using wkhtmltopdf for the purpose.

    when pdf is generated it breaks anywhere in tr tag.

    I want to avoid it .

  • fey
    fey over 10 years
    Thanks! I had this issue too but the fork you mentioned worked for me.
  • Nidhi
    Nidhi over 10 years
    Thanks for the information. Version 0.12.1 solves the page break issue.
  • Cerin
    Cerin over 9 years
    Note, this solution only works with the recent 0.12.1 version. Anything earlier still doesn't work.
  • z--
    z-- almost 9 years
    An answer below states 'wkhtmltopdf 0.12.2.1 onwards fixes the problem'. It would be good for this answer to be redited to show the current solution.
  • Joel Peltonen
    Joel Peltonen almost 9 years
    @Hannes Done, although I haven't checked myslef (no longer work with wkhtmltopdf)
  • EriF89
    EriF89 over 8 years
    I tried to get page-break-inside to work with wkhtmltopdf 0.12.2.4 using a modified version of Rotativa but without any success. Might be some problem in my markup or css though.
  • Hugh
    Hugh over 8 years
    I struggled with this for a couple of days. Turned out my table was in a div with a style of display: inline-block. Changed it to block and the with changes above it all started working!
  • Petrov
    Petrov over 8 years
    this was not the case for me - i can confirm even nested tables respected the page-breaks... the issue for me was more mac os vs ubuntu...
  • low_rents
    low_rents about 8 years
    I am using version 0.12.3.2 on windows and still have issues. maybe I just use the css wrong. where and how exactly do I put the page-break related CSS? inside the html-file i want to convert? inside @media print{} or inside @media screen{}? thanks for any help!
  • Joel Peltonen
    Joel Peltonen about 8 years
    @low_rents this question is a bit old and I'm not familiar with the latest situation any more. I never used @media at all. Have you tried to ask a new question with your situation explained? Maybe someone at the current wkhtmltopdf project could help better?
  • low_rents
    low_rents about 8 years
    @Nenotlep thanks for your answer. yes, I already posted a new question about this: stackoverflow.com/q/36334330/3391783 - it's funny how this all seemed to work back in 0.12.1-ish or 0.12.2-ish versions and is broken again in 0.12.3-ish versions.
  • Leslie Viljoen
    Leslie Viljoen almost 8 years
    I had a similar issue: my table was within a div with display: table-cell; applied. Making those styles @media only screen fixed the page breaks. If you can't get page breaks working, try to divide and conquer by removing half the CSS in stages and seeing if it works.
  • Mike Rockétt
    Mike Rockétt over 7 years
    I find it works best with the above solution, however table should be excluded. This leaves a good page-overflow, and retains thead duplications. If I leave the solution out altogether, then the overflowed cells collide with thead cells.
  • JosephK
    JosephK about 7 years
    This actually helps. Thank you!! Not sure why this is not the default behavior.
  • JosephK
    JosephK about 7 years
    I tried this on a group of tr elements - wrapping them within separate tbody elements - to try to keep certain groups of rows together. It had no effect. Doing this method without the "page-break-inside: avoid;" on the "tr" element caused a reversion to printing data on top of the page-headers, again (the "default" behavior).
  • Troy Morehouse
    Troy Morehouse about 7 years
    Yeah, I now apply the same "page-break-inside:avoid" rule on both tbody and tr and td's: "tbody,tbody>tr, tbody>tr>td, tbody>tr>th {page-break-inside:avoid;}" which appears to work in most situations.
  • JosephK
    JosephK about 7 years
    Thanks, but just tried that. It still page-breaks in the middle of my tbody groups of table-rows. I also tried adding a class to the tbody, and css on the class with the 'avoid' - no effect. I wish I knew what this was actually "doing" with the css-rule - maybe some way to make it think a group of trs is really 'one row' - but since making a tr 2x+ tall also breaks it, I'm guessing not. Maybe someone will make a usable HTML to PDF solution in another 10 years, but I think they are waiting for direct neural data-transfer, instead.
  • Niklas Rosencrantz
    Niklas Rosencrantz over 6 years
    It's been five years and this is still not working....Inconceivably bad support...
  • Joel Peltonen
    Joel Peltonen over 6 years
    @DjDacSaunders WKHTMLTOPDF is a hack, not a pure html -> pdf tool. The point of it is to render a very long document to a paged format. The fact that we have any control over this is great. If you want this to improve the absolute best place to contact is the upstream of wkhtml, which is either the QT project or perhaps the WebKit project. I foresee this thing as never changing as it's not really what WebKit was meant to do when rendering web pages as PDF files :/ For full control, perhaps try PrinceXML. (x)HTML is not a print format and "solutions" to that prob are always hacks.
  • Niklas Rosencrantz
    Niklas Rosencrantz over 6 years
    @Nenotlep Thanks for the comment. At the end I succeeded rendering pagebreaks correctly. What I did was remove all the CSS and just incrementally adding only the CSS that I needed. Then the pagebreaks displayed correctly.
  • UnixAgain
    UnixAgain over 6 years
    for me 0.12.1 does not solve the problem, and it takes toc away
  • Hugo
    Hugo over 4 years
    This worked for me. I'm using wkhtmltopdf 0.12.4. Thanks!
  • AMMAR ELHAMDO
    AMMAR ELHAMDO over 2 years
    you saved my time, thanks