A Developer's Guide to Building a Blazor PDF Viewer
Integrating a robust PDF viewer into a Blazor application can seem challenging, but it's a common requirement for business applications that need to generate invoices, reports, or other official documents. This guide provides a practical, peer-to-peer walkthrough on how to build a fully functional PDF viewer in a server-side Blazor application.
We'll move straight into the code, focusing on how to render PDFs from various sources like URLs and even directly from your Razor components. You'll also learn how to customize the PDF output and explore different ways to deliver the final document to your users, giving you a solid foundation for any PDF-related task in your Blazor projects.
Key Steps for Blazor PDF Viewing
- Add the IronPDF library to your Blazor C# project.
- Generate a PDF from a URL or an HTML string using the
ChromePdfRenderer
class. - Customize PDF generation with headers, footers, and custom margins using
ChromePdfRenderOptions
. - Display the generated PDF in the browser using an iframe or trigger a direct file download.
- Dynamically generate PDFs from Blazor Razor components for creating rich, data-driven documents.
Why Choose a Library for PDF Rendering in Blazor?
While you could try to build PDF rendering from scratch, a dedicated library like IronPDF handles the complexities of the PDF specification and browser rendering quirks for you. Its powerful Chrome rendering engine ensures that what you see in a modern web browser is exactly what you get in your PDF. This pixel-perfect conversion of HTML, CSS, and JavaScript saves immense development time and effort.
IronPDF is built for .NET developers, providing an intuitive API that feels right at home in a C# project. This makes tasks like HTML to PDF conversion, PDF customization, and document manipulation straightforward. While other libraries like Aspose and SyncFusion exist, IronPDF's focus on ease of use and rendering accuracy makes it a strong choice for Blazor applications.
How Do You Render a PDF from a URL in Blazor?
One of the most common needs is to convert an existing web page into a PDF. This is incredibly useful for archiving web content or generating a PDF version of a live report. With IronPDF, this process is accomplished with just a couple of lines of C#.
First, ensure you have IronPDF installed in your project. You can add it via the NuGet Package Manager by searching for IronPdf
or by using the Package Manager Console:
Install-Package IronPdf
Next, in your Razor component (.razor
file), you can create a method to handle the PDF generation. This method will use the ChromePdfRenderer
to fetch a URL and convert its content into a PDF document.
Code Example: URL to PDF
private async Task ViewCustomizedPdf()
{
var renderer = new ChromePdfRenderer();
// Create a set of rendering options to customize the PDF output.
var options = new ChromePdfRenderOptions
{
// Set a custom paper size, useful for invoices or specific document types.
PaperSize = PdfPaperSize.A4,
// Adjust margins to control the layout of the content.
MarginTop = 20, // in millimeters
MarginBottom = 20,
// Add a text header to every page.
TextHeader = new TextHeaderFooter
{
CenterText = "Report Generated from Blazor Application",
Font = PdfFont.Helvetica,
FontSize = 12
},
// Add a footer with dynamic content like page numbers and date.
// The {page} and {total-pages} fields are automatically populated.
TextFooter = new TextHeaderFooter
{
LeftText = "{date}",
RightText = "Page {page} of {total-pages}",
Font = PdfFont.Courier,
FontSize = 10
}
};
// Apply the custom options during the rendering process.
var pdf = await renderer.RenderUrlAsPdfAsync("https://getbootstrap.com/docs/5.3/examples/dashboard/", options);
pdfDataUri = $"data:application/pdf;base64,{Convert.ToBase64String(pdf.BinaryData)}";
}
private async Task ViewCustomizedPdf()
{
var renderer = new ChromePdfRenderer();
// Create a set of rendering options to customize the PDF output.
var options = new ChromePdfRenderOptions
{
// Set a custom paper size, useful for invoices or specific document types.
PaperSize = PdfPaperSize.A4,
// Adjust margins to control the layout of the content.
MarginTop = 20, // in millimeters
MarginBottom = 20,
// Add a text header to every page.
TextHeader = new TextHeaderFooter
{
CenterText = "Report Generated from Blazor Application",
Font = PdfFont.Helvetica,
FontSize = 12
},
// Add a footer with dynamic content like page numbers and date.
// The {page} and {total-pages} fields are automatically populated.
TextFooter = new TextHeaderFooter
{
LeftText = "{date}",
RightText = "Page {page} of {total-pages}",
Font = PdfFont.Courier,
FontSize = 10
}
};
// Apply the custom options during the rendering process.
var pdf = await renderer.RenderUrlAsPdfAsync("https://getbootstrap.com/docs/5.3/examples/dashboard/", options);
pdfDataUri = $"data:application/pdf;base64,{Convert.ToBase64String(pdf.BinaryData)}";
}
Private Async Function ViewCustomizedPdf() As Task
Dim renderer = New ChromePdfRenderer()
' Create a set of rendering options to customize the PDF output.
Dim options = New ChromePdfRenderOptions With {
.PaperSize = PdfPaperSize.A4,
.MarginTop = 20,
.MarginBottom = 20,
.TextHeader = New TextHeaderFooter With {
.CenterText = "Report Generated from Blazor Application",
.Font = PdfFont.Helvetica,
.FontSize = 12
},
.TextFooter = New TextHeaderFooter With {
.LeftText = "{date}",
.RightText = "Page {page} of {total-pages}",
.Font = PdfFont.Courier,
.FontSize = 10
}
}
' Apply the custom options during the rendering process.
Dim pdf = Await renderer.RenderUrlAsPdfAsync("https://getbootstrap.com/docs/5.3/examples/dashboard/", options)
pdfDataUri = $"data:application/pdf;base64,{Convert.ToBase64String(pdf.BinaryData)}"
End Function
How it Works
- We create an instance of
ChromePdfRenderer
, which is the core class for HTML-to-PDF conversion. - The
RenderUrlAsPdfAsync
method asynchronously fetches the HTML, CSS, and JavaScript from the specified URL and renders it into aPdfDocument
object. - The
pdf.BinaryData
property returns the raw byte array of the generated PDF. - We convert this byte array into a Base64 string and format it as a Data URI.
- This Data URI is then bound to the
src
attribute of an<iframe>
, prompting the browser's native PDF viewer to display the document.
How Can You Customize the PDF Generation?
Standard PDF conversion is great, but real-world applications often require more control. You might need to add headers and footers with page numbers, adjust margins, or change the paper size. IronPDF exposes these options through the ChromePdfRenderOptions
class.
By configuring these options, you can tailor the PDF output to match specific requirements, such as formatting for professional reports or invoices.
Code Example: Custom Headers and Footers
Let's expand on the previous example to include a custom header and footer. The header will display the document title, and the footer will show the current date and page number.
private async Task ViewCustomizedPdf()
{
var renderer = new ChromePdfRenderer();
// Create a set of rendering options to customize the PDF output.
var options = new ChromePdfRenderOptions
{
// Set a custom paper size, useful for invoices or specific document types.
PaperSize = PdfPaperSize.A4,
// Adjust margins to control the layout of the content.
MarginTop = 20, // in millimeters
MarginBottom = 20,
// Add a text header to every page.
TextHeader = new TextHeaderFooter
{
CenterText = "Report Generated from Blazor Application",
Font = PdfFont.Helvetica,
FontSize = 12
},
// Add a footer with dynamic content like page numbers and date.
// The {page} and {total-pages} fields are automatically populated.
TextFooter = new TextHeaderFooter
{
LeftText = "{date}",
RightText = "Page {page} of {total-pages}",
Font = PdfFont.Courier,
FontSize = 10
}
};
// Apply the custom options during the rendering process.
var pdf = await renderer.RenderUrlAsPdfAsync("https://getbootstrap.com/docs/5.3/examples/dashboard/", options);
pdfDataUri = $"data:application/pdf;base64,{Convert.ToBase64String(pdf.BinaryData)}";
}
private async Task ViewCustomizedPdf()
{
var renderer = new ChromePdfRenderer();
// Create a set of rendering options to customize the PDF output.
var options = new ChromePdfRenderOptions
{
// Set a custom paper size, useful for invoices or specific document types.
PaperSize = PdfPaperSize.A4,
// Adjust margins to control the layout of the content.
MarginTop = 20, // in millimeters
MarginBottom = 20,
// Add a text header to every page.
TextHeader = new TextHeaderFooter
{
CenterText = "Report Generated from Blazor Application",
Font = PdfFont.Helvetica,
FontSize = 12
},
// Add a footer with dynamic content like page numbers and date.
// The {page} and {total-pages} fields are automatically populated.
TextFooter = new TextHeaderFooter
{
LeftText = "{date}",
RightText = "Page {page} of {total-pages}",
Font = PdfFont.Courier,
FontSize = 10
}
};
// Apply the custom options during the rendering process.
var pdf = await renderer.RenderUrlAsPdfAsync("https://getbootstrap.com/docs/5.3/examples/dashboard/", options);
pdfDataUri = $"data:application/pdf;base64,{Convert.ToBase64String(pdf.BinaryData)}";
}
Private Async Function ViewCustomizedPdf() As Task
Dim renderer = New ChromePdfRenderer()
' Create a set of rendering options to customize the PDF output.
Dim options = New ChromePdfRenderOptions With {
.PaperSize = PdfPaperSize.A4,
.MarginTop = 20,
.MarginBottom = 20,
.TextHeader = New TextHeaderFooter With {
.CenterText = "Report Generated from Blazor Application",
.Font = PdfFont.Helvetica,
.FontSize = 12
},
.TextFooter = New TextHeaderFooter With {
.LeftText = "{date}",
.RightText = "Page {page} of {total-pages}",
.Font = PdfFont.Courier,
.FontSize = 10
}
}
' Apply the custom options during the rendering process.
Dim pdf = Await renderer.RenderUrlAsPdfAsync("https://getbootstrap.com/docs/5.3/examples/dashboard/", options)
pdfDataUri = $"data:application/pdf;base64,{Convert.ToBase64String(pdf.BinaryData)}"
End Function
Key Customization Features
- Page Layout: Control properties like
PaperSize
,Orientation
, and margins (MarginTop
,MarginBottom
, etc.) for precise document layout. - Headers and Footers: The
TextHeader
andTextFooter
properties allow you to add text and dynamic fields. You can also useHtmlHeader
andHtmlFooter
for more complex, HTML-based content. For more details, see the Header and Footer guide. - Rendering Delay: Use
RenderDelay
to wait for JavaScript animations or async data loading on a page to complete before generating the PDF. - CSS Media Type: Set
CssMediaType
toPdfCssMediaType.Print
to apply print-specific CSS styles, just like a browser's print function.
What's the Best Way to Serve a PDF to the User?
Displaying the PDF in an <iframe>
is convenient for a quick preview, but it's not always the best user experience. Sometimes, you want the user to download the file directly. This can be achieved in Blazor by streaming the file from a controller endpoint or a minimal API.
Here's how you can create a method that generates a PDF and returns it as a downloadable file.
Code Example: Triggering a File Download
// This method would typically be in a Blazor @page, a controller, or a minimal API endpoint.
// For this example, let's assume it's a method that can be called to get a FileResult.
public async Task<IResult> DownloadPdf()
{
var renderer = new ChromePdfRenderer();
var pdf = await renderer.RenderHtmlAsPdfAsync("<h1>PDF Report</h1><p>This is a downloadable PDF generated from a Blazor app.</p>");
// Return the PDF as a file stream.
// This prompts the browser's "Save As" dialog.
return Results.File(pdf.BinaryData, "application/pdf", "MyReport.pdf");
}
// This method would typically be in a Blazor @page, a controller, or a minimal API endpoint.
// For this example, let's assume it's a method that can be called to get a FileResult.
public async Task<IResult> DownloadPdf()
{
var renderer = new ChromePdfRenderer();
var pdf = await renderer.RenderHtmlAsPdfAsync("<h1>PDF Report</h1><p>This is a downloadable PDF generated from a Blazor app.</p>");
// Return the PDF as a file stream.
// This prompts the browser's "Save As" dialog.
return Results.File(pdf.BinaryData, "application/pdf", "MyReport.pdf");
}
' This method would typically be in a Blazor @page, a controller, or a minimal API endpoint.
' For this example, let's assume it's a method that can be called to get a FileResult.
Public Task As async
Private IResult And gt
'INSTANT VB WARNING: The following constructor is declared outside of its associated class:
'ORIGINAL LINE: DownloadPdf()
Private Sub New()
Dim renderer = New ChromePdfRenderer()
Dim pdf = Await renderer.RenderHtmlAsPdfAsync("<h1>PDF Report</h1><p>This is a downloadable PDF generated from a Blazor app.</p>")
' Return the PDF as a file stream.
' This prompts the browser's "Save As" dialog.
Return Results.File(pdf.BinaryData, "application/pdf", "MyReport.pdf")
End Sub
This approach is often cleaner, as it doesn't embed the PDF within your application's UI and gives the user a portable file they can save and share. You can learn more about saving and exporting options from our documentation on saving PDFs.
How Do You Generate a PDF from a Razor Component?
Perhaps the most powerful feature for Blazor developers is the ability to generate a PDF directly from a Razor component. This allows you to create dynamic, data-driven documents using the same component model you already know. You can design an invoice, a ticket, or a report as a component, pass data to it, render it to an HTML string, and then convert that string to a PDF.
This requires a helper service to render the component to HTML outside of the normal page rendering context.
1. Create the Razor Component for the PDF
First, create your component. This could be an invoice template, for example.
Invoice.razor
@* This component is designed specifically for PDF rendering. *@
<h3>Invoice #@InvoiceNumber</h3>
<p>Date: @DateTime.Now.ToShortDateString()</p>
<table class="table">
<thead>
<tr><th>Item</th><th>Price</th></tr>
</thead>
<tbody>
@foreach (var item in LineItems)
{
<tr><td>@item.Key</td><td>@item.Value.ToString("C")</td></tr>
}
</tbody>
</table>
@code {
[Parameter]
public int InvoiceNumber { get; set; }
[Parameter]
public Dictionary<string, decimal> LineItems { get; set; } = new();
}
@* This component is designed specifically for PDF rendering. *@
<h3>Invoice #@InvoiceNumber</h3>
<p>Date: @DateTime.Now.ToShortDateString()</p>
<table class="table">
<thead>
<tr><th>Item</th><th>Price</th></tr>
</thead>
<tbody>
@foreach (var item in LineItems)
{
<tr><td>@item.Key</td><td>@item.Value.ToString("C")</td></tr>
}
</tbody>
</table>
@code {
[Parameter]
public int InvoiceNumber { get; set; }
[Parameter]
public Dictionary<string, decimal> LineItems { get; set; } = new();
}
Friend * This component is designed specifically for PDF rendering. * (Of h3) Invoice #InvoiceNumber</h3> (Of p) [Date]
Inherits DateTime.Now.ToShortDateString()</p> <table class="table">(Of thead) (Of tr)(Of th) Item</th>(Of th) Price</th></tr> </thead> (Of tbody) foreach(var item in LineItems)
(Of tr)(Of td) item.Key</td>(Of td) item.Value.ToString("C")</td></tr>
End Class
'INSTANT VB TODO TASK: Local functions are not converted by Instant VB:
' </tbody> </table> @code
' {
' [Parameter] public int InvoiceNumber
' {
' get;
' set;
' }
'
' [Parameter] public Dictionary<string, decimal> LineItems
' {
' get;
' set;
' } = New();
'}
2. Render the Component to an HTML String and Convert to PDF
Next, use this component in your main page to generate the PDF.
private async Task GeneratePdfFromComponent()
{
// This is a simplified example. In a real app, you'd use a service
// to render the component to an HTML string.
// For the sake of this tutorial, we'll build the HTML manually
// to simulate rendering a component.
var invoiceData = new Dictionary<string, decimal>
{
{ "IronPDF License", 799m },
{ "Support Package", 299m }
};
var html = $@"
<h1>Invoice #123</h1>
<p>Date: {DateTime.Now.ToShortDateString()}</p>
<table border='1' width='100%'>
<thead>
<tr><th>Item</th><th>Price</th></tr>
</thead>
<tbody>";
foreach (var item in invoiceData)
{
html += $"<tr><td>{item.Key}</td><td>${item.Value}</td></tr>";
}
html += "</tbody></table>";
var renderer = new ChromePdfRenderer();
var pdf = await renderer.RenderHtmlAsPdfAsync(html);
// Now you can either display it in an iframe or save it.
await pdf.SaveAsAsync("GeneratedInvoice.pdf");
pdfDataUri = $"data:application/pdf;base64,{Convert.ToBase64String(pdf.BinaryData)}";
}
private async Task GeneratePdfFromComponent()
{
// This is a simplified example. In a real app, you'd use a service
// to render the component to an HTML string.
// For the sake of this tutorial, we'll build the HTML manually
// to simulate rendering a component.
var invoiceData = new Dictionary<string, decimal>
{
{ "IronPDF License", 799m },
{ "Support Package", 299m }
};
var html = $@"
<h1>Invoice #123</h1>
<p>Date: {DateTime.Now.ToShortDateString()}</p>
<table border='1' width='100%'>
<thead>
<tr><th>Item</th><th>Price</th></tr>
</thead>
<tbody>";
foreach (var item in invoiceData)
{
html += $"<tr><td>{item.Key}</td><td>${item.Value}</td></tr>";
}
html += "</tbody></table>";
var renderer = new ChromePdfRenderer();
var pdf = await renderer.RenderHtmlAsPdfAsync(html);
// Now you can either display it in an iframe or save it.
await pdf.SaveAsAsync("GeneratedInvoice.pdf");
pdfDataUri = $"data:application/pdf;base64,{Convert.ToBase64String(pdf.BinaryData)}";
}
Private Async Function GeneratePdfFromComponent() As Task
' This is a simplified example. In a real app, you'd use a service
' to render the component to an HTML string.
' For the sake of this tutorial, we'll build the HTML manually
' to simulate rendering a component.
Dim invoiceData = New Dictionary And lt
'INSTANT VB TODO TASK: Local functions are not converted by Instant VB:
' string, decimal>
' {
' {
' "IronPDF License", 799m
' }
' ,
' {
' "Support Package", 299m }
' };
'
' var html = string.Format("
' <h1>Invoice #123</h1>
' <p>Date: {0}</p>
' <table border='1' width='100%'>
' <thead>
' <tr><th>Item</th><th>Price</th></tr>
' </thead>
' <tbody>", DateTime.Now.ToShortDateString());
'
' foreach (var item in invoiceData)
' {
' html += string.Format("<tr><td>{0}</td><td>${1}</td></tr>", item.Key, item.Value);
' }
'
' html += "</tbody></table>";
'
' var renderer = New ChromePdfRenderer();
' var pdf = await renderer.RenderHtmlAsPdfAsync(html);
'
' ' Now you can either display it in an iframe or save it.
' await pdf.SaveAsAsync("GeneratedInvoice.pdf");
' pdfDataUri = string.Format("data:application/pdf;base64,{0}", Convert.ToBase64String(pdf.BinaryData));
'}
This approach unlocks the full power of Blazor's component model for PDF generation, enabling you to create complex, reusable, and easily maintainable document templates.
A PDF generated by IronPDF from a sample Blazor component, demonstrating how web content is accurately rendered and displayed in the browser.
What Other PDF Features Can Be Used in Blazor?
Beyond viewing and generating, a full-featured PDF library can handle many other tasks within your Blazor app. With IronPDF, you can also:
- Merge and Split PDFs: Combine multiple
PdfDocument
objects into one or split a single PDF into multiple files. - Edit and Secure Documents: Add watermarks, text, and images to existing PDFs. You can also apply password protection and encryption to secure your documents.
- Extract Data: Read text and extract images from PDF files, which is useful for processing incoming documents.
These capabilities allow you to build comprehensive document workflows directly within your .NET applications.
Conclusion
Integrating a PDF viewer and generator into a server-side Blazor application is a straightforward process with a library like IronPDF. We've seen how to move beyond basic HTML to PDF conversion and leverage the power of ChromePdfRenderOptions
for customization, serve files for a better user experience, and even generate dynamic documents directly from your Razor components.
By using these techniques, you can add powerful document generation features to your Blazor projects, saving time and creating professional, pixel-perfect PDFs with ease.
Start using IronPDF in your project today with a free trial.
Frequently Asked Questions
How can I integrate a PDF viewer in a server-side Blazor application?
You can integrate a PDF viewer in a server-side Blazor application using the IronPDF library. This involves generating the PDF and then displaying it using an iframe
with a Base64 Data URI. For instance, convert the PDF binary data to a Base64 string and set it as the src
of the iframe
.
Can I render PDFs from external URLs in Blazor?
Yes, you can render PDFs from external URLs in Blazor using IronPDF. Use the RenderUrlAsPdf
method to fetch the HTML content from the URL and convert it into a PDF document.
How do I customize PDF output with headers and footers in my Blazor app?
To customize PDF output with headers and footers in a Blazor app, use the ChromePdfRenderOptions
class. You can set properties like TextHeader.CenterText
and TextFooter.RightText
to add custom text, including dynamic fields like {page}
and {total-pages}
.
What are the methods for delivering a PDF to a user in a Blazor application?
In a Blazor application, you can deliver a PDF by embedding it within an iframe
using a Base64 Data URI for inline viewing, or by implementing a file download endpoint using FileResult
to allow users to save the PDF to their device.
How can I generate a PDF from HTML in a Blazor application?
In a Blazor application, you can generate a PDF from HTML using IronPDF's RenderHtmlAsPdfAsync
method. First, ensure the HTML content is properly formatted, then pass it to this method to create a PDF document.
Is it possible for a Blazor application to support complex JavaScript when rendering a PDF?
Yes, IronPDF supports complex JavaScript while rendering a PDF in a Blazor application. You can adjust the RenderDelay
in ChromePdfRenderOptions
to ensure all JavaScript executes before capturing the page as a PDF.
How do I set the paper size and margins when generating a PDF in C#?
To set the paper size and margins when generating a PDF in C#, use the ChromePdfRenderOptions
class. Specify the PaperSize
and adjust the MarginTop
, MarginBottom
, MarginLeft
, and MarginRight
properties as needed.