PrintPdfButton
PrintPdfButton is a ready-made button that opens the browser's
native print dialog for a PDF you generate on the server. You supply
a callback that writes PDF bytes to an OutputStream; the component
takes care of streaming the bytes to the browser and triggering
print via the classic hidden-iframe trick that web apps have used
for decades.
When to use it
- You want to print a server-side generated PDF (invoice, report, label) directly from a Vaadin view without first downloading it to disk.
- You already have, or are happy to add, a PDF library such as Apache PDFBox, OpenPDF, iText, Flying Saucer, etc.
If you only need to offer the PDF as a download, use
DynamicFileDownloader instead.
Basic usage
Pass a lambda that writes PDF bytes to the given OutputStream. The
stream is connected to the response body, so whatever you write ends
up in the browser's print preview. The callback may throw
IOException, so you can delegate straight to PDF-library calls
without extra try/catch plumbing:
add(new PrintPdfButton(out ->
writePdf("It is " + LocalDateTime.now(), out)));
The default constructor gives you a printer-icon-only button. A second constructor adds a text label (and drops the icon):
add(new PrintPdfButton("Print receipt", out -> writePdf(receipt, out)));
Generating the PDF
Any library that can write to an OutputStream works. The following
example uses Apache PDFBox:
private static void writePdf(String content, OutputStream out) throws IOException {
PDDocument document = new PDDocument();
PDPage page = new PDPage(PDRectangle.A4);
document.addPage(page);
PDPageContentStream contentStream =
new PDPageContentStream(document, page);
contentStream.beginText();
contentStream.newLineAtOffset(20, 700);
contentStream.setFont(
new PDType1Font(Standard14Fonts.FontName.COURIER), 16);
contentStream.showText(content);
contentStream.endText();
contentStream.close();
document.save(out);
document.close();
}
PDFBox is not a dependency of Flow Viritin – add your PDF library of choice to your own project.
Customising the response
For extra control over the HTTP response – for instance, to set a
Content-Disposition header that influences the suggested filename
in the browser's print dialog – subclass and override the protected
writePdf(PdfWriterCallback, VaadinResponse) hook:
PrintPdfButton button = new PrintPdfButton(out -> writePdf(receipt, out)) {
@Override
protected void writePdf(PdfWriterCallback cb, VaadinResponse response) throws IOException {
response.setHeader("Content-Disposition", "inline; filename=\"receipt.pdf\"");
super.writePdf(cb, response);
}
};
How it works
On click, the component:
- Creates a hidden
<iframe>whosesrcis served by a dynamic VaadinElementRequestHandler. - Writes
application/pdfto the response via your callback. - Once the iframe finishes loading, calls
contentWindow.print()from a small inline script.
A new iframe is created for every click; the previous one is removed first, so repeated prints do not accumulate stale DOM nodes.
Notes and caveats
- The browser's print dialog pops up, not a download. If the user cancels, nothing is saved.
- Popup- or iframe-blocking browser extensions can interfere; the technique itself is well established and works in current Chrome, Firefox, Edge and Safari.
- The suggested filename in the print dialog is whatever the browser
picks from the iframe URL by default; override
writePdfand set aContent-Dispositionheader to control it explicitly.
