Skip to main content
Ben Nadel at cf.Objective() 2011 (Minneapolis, MN) with: Emily Meyer
Ben Nadel at cf.Objective() 2011 (Minneapolis, MN) with: Emily Meyer

Ask Ben: Optimizing Tables For Printing

By
Published in , Comments (27)

Hey I have a report I want to print but keep the header on every page, column names. Any suggestions?

HTML table elements are actually designed to allow for this very functionality. The trick is that you have to use the THEAD tag which defines the table header. By using the THEAD tag, the rows that you define within the THEAD tag will be displayed at the top of every printed page. Additionally, you can use the TFOOT tag to define the table footer. By using the TFOOT tag, the rows that you define within the TFOOT tag will be displayed at the bottom of every page.

Let's take a look at some sample HTML that has a long table that makes use of both the THEAD and TFOOT HTML tags:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
	<title>Table Printing Demo</title>

	<style type="text/css">

		body {
			font-family: verdana, arial, sans-serif ;
			font-size: 12px ;
			}

		th,
		td {
			padding: 4px 4px 4px 4px ;
			text-align: center ;
			}

		th {
			border-bottom: 2px solid #333333 ;
			}

		td {
			border-bottom: 1px dotted #999999 ;
			}

		tfoot td {
			border-bottom-width: 0px ;
			border-top: 2px solid #333333 ;
			padding-top: 20px ;
			}

	</style>

</head>
<body>

	<cfoutput>

		<h1>
			Table Print Demonstration
		</h1>

		<p>
			This demonstrates how to properly define an HTML table
			in such a way that it will display the table header on
			each of the printed pages.
		</p>


		<table
			cellspacing="0"
			summary="This is a really long table that is used to demonstrate the print of headers across several pages.">

		<!---
			Define the HEAD of the table. This is the data that
			will be displayed at the top of every printed page.
		--->
		<thead>
			<tr>
				<th>
					ID
				</th>
				<th>
					Value
				</th>
			</tr>
		</thead>

		<!---
			Defint eh FOOTER of the table. This is the data that
			will be displayed at the bottom of every printed page.
		--->
		<tfoot>
			<tr>
				<td colspan="2">
					Kinky Solutions Table Demo
				</td>
			</tr>
		</tfoot>

		<!--- Define the BODY of the table. This is the data. --->
		<tbody>

			<!---
				Let's now create a ton or rows that will require
				several pages to fully print.
			--->
			<cfloop
				index="intRow"
				from="1"
				to="100"
				step="1">

				<tr>
					<td>
						#intRow#
					</td>
					<td>
						#RandRange( 111111, 999999 )#
					</td>
				</tr>

			</cfloop>

		</tbody>
		</table>

	</cfoutput>

</body>
</html>

Now, when we go to view the print preview of the page, this is what we get:

Table Header And Footer Gets Printed On All Pages When You Use The THEAD and TFOOT Tags Respectively.

Notice that the header and footer data of the table are displayed on all pages that are required to print the table data.

Want to use code from this post? Check out the license.

Reader Comments

15,880 Comments

@B,

You should just be able to wrap this in a CFDocument tag, but I have not test that. I can see if I carve out a few minutes.

55 Comments

How come CFTABLE doesn't do that? :)

I had high hopes for CFTABLE, but every time I use it, my boss will ask me to give him strip colour...

Bam! back to reality.

Then I'll have to go back to the good old CFOUTPUT... until CSS3 is available or use jQuery.

1 Comments

To me, the TABLE element is a constant source of surprises ;-) Until recently, I was not aware of the COL element for instance which allows a great deal of flexible styling and markup with touching individual table cells.

15,880 Comments

@Robert,

I am a big fan of the COL tag to define column widths, but I have had some trouble getting it to work with other styles. What kind of styles are you finding work nicely?

16 Comments

Now if only IE would support these tags properly. (I'm the millionth person to post that sentence - I win!)

I'm currently working on migrating a bunch of reports from Access (don't ask) to CF. One of them displays information for a bunch of different vendors, a couple of pages per vendor, and shows vendor name and phone number in the page footer.

Using TFOOT puts me closer than anything else I've tried: in Firefox, the footer is displayed at the bottom of all pages but the last for each vendor, which is fine. (On the last vendor page, it's displayed at the bottom of the content.) Unfortunately, there are very few people here who use Firefox, so my solutions have to work in IE. :(

Oh yes, did I mention that the intranet (where the reports are housed) is currently running on MX 6?

Hopefully I will get some time soon to start moving our sites to CF 8 ... at the last place I worked, we didn't even use 6, just went straight from 5 to MX 7 ...

15,880 Comments

@Dave,

Oh my god! I feel like such an idiot. Can you believe that I didn't even test this solution in Internet Explorer (IE). For some reason, I just assumed that the way tables were handled when printing was handled the same across all browsers. I guess, I just categorized it as part of the print driver or something.

But, I just tested the above in IE7, and you are correct - this doesn't work at all. Lame!!!

15,880 Comments

I just tried this with CFDocument as well and I am disappointed to report that the PDF does not print the table header properly either! Not cool :(

16 Comments

@Ben,

I can believe it ... I've run into something similar two or three times already on this project. Usually it's been when my boss asked how a report was coming along, and I showed him in Firefox. We open IE aaaaand it's back to the drawing board.

Maybe IE 8 will reach the same level of CSS compliance as Firefox ... I'd try the beta but I'm afraid of it. :)

3 Comments

i just came across this. i'd seen people use thead before, but i didn't see the point. i was excited to go out and try it. started testing.. not only does it not work in ie, but it appears this is simply a ff feature. opera, safari and chrome don't seem to do this operation either... it is a nice feature though.

2 Comments

Man, that scared me a bit. I thought I had been missing something all this time that would've been real useful. What a relief to realize I hadn't. I just googled THEAD and saw you can use this: <style> thead { display: table-header-group; } </style>. But then IE doesn't break the table cleanly - you get vertical lines that have been cut off halfway. Of course a workaround in CF is to use <cfsavecontent variable="tableHeader"><tr><th>Col1</th><th>Col2</th></cfsavecontent>, count lines, close your table, then insert a page break - <p style="page-break-after: always; color:white;">.</p>

16 Comments

The problem with that workaround in my case is that I have several fields that are basically memo/text/clob fields, so I can't even be sure how many lines I'm displaying on a "page", and there's one particular section of the report that can be repeated often enough that it might take up more than one page on its own ...

Well, okay, actually the problem in my case is that we're trying to take a report that was designed specifically for Access and preserve the appearance but also make it look good as an HTML report printed on paper. :)

15,880 Comments

I feel bad - that I thought this stuff was all cross-browser. I didn't mean to mislead or panic anyone.

... however, let's not forget that using THEAD and TFOOT does have a number of benefits! For starters, it's simply good, semantic HTML. But, more than that, using THEAD and TFOOT gives us many CSS hooks to help style our tables without additional class names.

8 Comments

I ended up going back to font= and basic table tags to get pages to display across browser type and print with header and footer.

Works well enough.

3 Comments

not to mention you can use jquery to sort the columns in the dom rather than another page request. you have to use the thead, th, tbody of the table. working on something in that now.

2 Comments

@Dave

For memo/text/clob/etc fields, you can determine the number of characters in the data, estimate the number of characters per line and calculate when to break a page. Of course with most fonts that will only be an estimate, as some letters (ie, WWWWW) would be longer than others (ie, IIIII). There are fixed-width fonts like Courier New, that if you're users don't mind the look of them, would allow you to calculate exactly when to break a page. Oh, one other thing, in the table style I fix the width in centimeters (rather than px, em, etc) b/c that seems to work across different PCs and printers in IE (not sure of the other browsers). 17.5cm for portrait and 23.5cm for landscape. Eg., <table style="width:17.5cm;">.

@Ben

No worries.

16 Comments

@Ray

It's true, I could probably fake a page footer by tracking the approximate position on the page and inserting whatever would be necessary to put a div with my "page footer" near the bottom of each page, with a break to follow ... I've done stuff like that in Excel before for similar reasons (long report sections that people wanted to view on paper rather than electronically).

It's just disappointing to have to put in all this extra code! If they could just support the same properties and features ... grr ...

By the way, specifying a width in cm (in a style, because you can't do it in the width property of a table) works fine in Firefox 3, and it seems to work in Chrome as well, although without a print preview function, I can't tell for sure (on my screen, the text in Chrome appears to be as wide as the text in Firefox).

11 Comments

@Mallik (or Ben),

Did you ever get/figure out an answer to this question of selective display of header/footer?

For a job at work, using CF 8.01 (all patches applied, as far as I know,) we are hoping that there is a way to manipulate the "cfdocumentitem" tag logic such as to selectively control which pages a header (or footer) actually appears on.

For example, we want to not display the header on the first page, but to go ahead and display it on every page thereafter.

Our main issue so far is that when trying to reference the "cfdocument.currentpagenumber" inside the "cfdocumentitem" tag, CF complains that the variable doesn't exist. (A problem I have seen other have experienced: http://blog.dkferguson.com/index.cfm/2008/1/11/CFDocument--pdf-generation-broke-after-CF8-upgrade )

"Any advice you could give me that might point me the way of success would be, by me, appreciated." - Ainsley Hayes, The West Wing

"Well, not speaking in iambic pentameter might be a step in the right direction." - Lionel Tribbey, The West Wing

Thanks all,

David L.

I believe in love. I believe in compassion. I believe in human rights. I believe that we can afford to give more of these gifts to the world around us because it costs us nothing to be decent and kind and understanding. And, I want you to know that when you land on this site, you are accepted for who you are, no matter how you identify, what truths you live, or whatever kind of goofy shit makes you feel alive! Rock on with your bad self!
Ben Nadel