Visualforce PDF Repeating Headers and Footers
Updated 04-21-2013: Article modified to point download link to GitHub repository. Format was cleaned up to match new site theme and information related to download removed as it is now presented on the Github page.
Currently there is no native support for repeating headers and footers for Salesforce.com Visualforce pages that are rendered as PDF documents. The solution in the past has been to hardcode page breaks, headers and footers and hope that the content doesn't push the layout out of whack (which it always did).
So I spent quite a bit of time trying to figure out a solution. After some experimentation with various techniques I centered on a CSS approach that works really well and even allows for first page or last page only headers/footers to be specified with some creative layout of html tags.
I posted my original solution to the discussion boards and found I wasn't the only one that had been looking to solve this issue. After working with the tags a bit more and wanting to simplify the process I came up with a component that handles creating the elements so that they have the proper CSS tags. The end result is a Visualforce component called PDFHeaderFooter and also a CSS file to accompany it called PDFDocumentStyle.
The component has allowed for code-reuse across all of the PDF generated documents that I have had to provide for my users. I originally wrote the code into a template document that set the header and footer and used a component tag to pull in the unique content for each document but I found this to be inflexible in many areas forcing the creation of a lot of custom attributes that were relevent only to specific documents. The component approach has allowed me to keep the unique requirements of each document in the document itself leaving the component to control the layout of the content in the header or footer.
Below is a list of attributes supported by the PDFHeaderFooter component:
Attribute | Values | Description |
---|---|---|
Type | header, footer | Determines if the component renders the text in the header area or the footer area. |
Position | left, right, center | Controls the position of the text. |
ShowPageNumbers | true, false | Set to true to display the page numbers at the specified type and position |
PDFDocument Sample:
<apex:page renderas="pdf">
<!-- Stylesheets -->
<apex:stylesheet value="{!$Resource.PDFDocumentStyle}" />
<!-- First Page Header -->
<c:PDFHeaderFooter type="header" position="left">
<div style="padding: 10px; background-color: #ccc">Your Logo Here</div>
</c:PDFHeaderFooter>
<c:PDFHeaderFooter type="header" position="center">First Center Header Text</c:PDFHeaderFooter>
<c:PDFHeaderFooter type="header" position="right">First Right Header Text</c:PDFHeaderFooter>
<!-- All Pages Header -->
<c:PDFHeaderFooter type="header" position="left">
<div style="padding: 10px; background-color: #ccc">Your Logo Here</div>
</c:PDFHeaderFooter>
<c:PDFHeaderFooter type="header" position="center">Second Center Header Text</c:PDFHeaderFooter>
<c:PDFHeaderFooter type="header" position="right">Second Right Header Text</c:PDFHeaderFooter>
<!-- All Pages Footer -->
<c:PDFHeaderFooter type="footer" position="left">First Left Footer Text</c:PDFHeaderFooter>
<c:PDFHeaderFooter type="footer" position="center">First Center Footer Text</c:PDFHeaderFooter>
<c:PDFHeaderFooter type="footer" position="right" showPageNumbers="true"/>
<!-- Content -->
<h1 style="padding-top: 3000px; background-color: #eee;">My Test Document</h1>
<p>Test text</p>
<!-- Last Page Footer -->
<c:PDFHeaderFooter type="footer" position="left">Second Left Footer Text</c:PDFHeaderFooter>
<c:PDFHeaderFooter type="footer" position="center">Second Center Footer Text</c:PDFHeaderFooter>
<c:PDFHeaderFooter type="footer" position="right" showPageNumbers="true"/>
</apex:page>
You will notice that the PDFDocument sample demonstrates the ability to create a header with a unique first page header and a footer with a unique last page footer. It does this using a set of header tags that represents the first page which is followed by a second set of header tags that will become the header for all other pages that follow.
The footer uses a different technique to create the last page footer. First you need to add in the footer tags that you want to display on all pages. Then add your page content. Once you have completed your page content then you can add another set of footer tags which will then represent the footer of the last page.
That is all there is to it. My goal was to keep the solution as simple as possible in hopes that it would allow it to be flexible in many different scenarios. For instance, I used the component (without modification) to create a draft watermark that repeated on every page by setting a translucent watermark image in the center header tag and added some top margin using css to push it down to the center of the page. This allowed the watermark to repeat for each page.
Give it a try and let me know how it works out.
Download the source code from GitHub using the link below:
Download Source