How to Display a PDF in Blazor (Guide)
Introduction
Blazor display PDF functionality in modern web applications requires a robust PDF viewer component that goes beyond basic browser capabilities. For .NET developers building Blazor applications, IronPDF provides a powerful PDF viewer solution that seamlessly integrates with your Blazor Server app. This enables you to display PDF documents with high performance and rich functionality without relying on third-party browser tools.
In this tutorial, we'll explore how to implement a Blazor PDF viewer using IronPDF, creating a PDF viewer component that can open PDF files, handle PDF content, and provide users with an intuitive interface for displaying PDF on both desktop and mobile phones.
Getting Started Displaying PDFs with IronPDF
Before implementing your Blazor PDF viewer, you'll need to install IronPDF. Add it to your Blazor Server app through NuGet:
Install-Package IronPdf
Next, create a new Blazor application and ensure you have the latest version of .NET Core installed. Store your PDF files in the wwwroot folder for easy access, or prepare to load them from other sources like byte arrays or URLs.
Creating Your First Blazor PDF Viewer Component
Let's build a basic Blazor PDF viewer component that can display PDF documents. First, create a new Razor component:
@page "/pdfviewer"
@rendermode InteractiveServer
@using IronPdf
@inject IJSRuntime JSRuntime
@inject Microsoft.AspNetCore.Hosting.IWebHostEnvironment WebHostEnvironment
<h3>PDF Viewer Component</h3>
<div>
<button @onclick="LoadPdfDocument">Open File</button>
<div id="pdfContainer">
@if (!string.IsNullOrEmpty(pdfUrl))
{
<iframe src="@pdfUrl" style="width:100%; height:600px;"></iframe>
}
</div>
</div>
@code {
private string pdfUrl = "";
private byte[] pdfData;
private async Task LoadPdfDocument()
{
// Load PDF from file
var pdfDocument = PdfDocument.FromFile("wwwroot/sample.pdf");
pdfData = pdfDocument.BinaryData;
// Create object URL for display
pdfUrl = await CreateObjectUrl(pdfData);
}
private async Task<string> CreateObjectUrl(byte[] data)
{
var base64 = Convert.ToBase64String(data);
return $"data:application/pdf;base64,{base64}";
}
}@page "/pdfviewer"
@rendermode InteractiveServer
@using IronPdf
@inject IJSRuntime JSRuntime
@inject Microsoft.AspNetCore.Hosting.IWebHostEnvironment WebHostEnvironment
<h3>PDF Viewer Component</h3>
<div>
<button @onclick="LoadPdfDocument">Open File</button>
<div id="pdfContainer">
@if (!string.IsNullOrEmpty(pdfUrl))
{
<iframe src="@pdfUrl" style="width:100%; height:600px;"></iframe>
}
</div>
</div>
@code {
private string pdfUrl = "";
private byte[] pdfData;
private async Task LoadPdfDocument()
{
// Load PDF from file
var pdfDocument = PdfDocument.FromFile("wwwroot/sample.pdf");
pdfData = pdfDocument.BinaryData;
// Create object URL for display
pdfUrl = await CreateObjectUrl(pdfData);
}
private async Task<string> CreateObjectUrl(byte[] data)
{
var base64 = Convert.ToBase64String(data);
return $"data:application/pdf;base64,{base64}";
}
}IRON VB CONVERTER ERROR developers@ironsoftware.comThis code creates a simple PDF viewer component that loads a PDF document and displays it using an iframe. The LoadPdfDocument method reads PDF files from the same path (wwwroot folder) and converts them to a byte array. The CreateObjectUrl method then transforms this byte array into a data URL that the iframe can display, allowing users to easily view the loaded PDF document.
Output

Implementing JavaScript Interop for Enhanced Display
For better control over PDF content display, we can use JavaScript functions to handle the PDF viewer functionality:
@page "/pdf-jsinterop"
@rendermode InteractiveServer
@using IronPdf
@inject IJSRuntime JSRuntime
@inject Microsoft.AspNetCore.Hosting.IWebHostEnvironment WebHostEnvironment
<h3>IronPDF JavaScript Interop Viewer</h3>
<p>Displays PDF using JavaScript's Blob/ObjectURL capabilities.</p>
@if (!string.IsNullOrEmpty(ErrorMessage))
{
<div class="alert alert-danger">Error: @ErrorMessage</div>
}
<div id="@documentId" style="border: 1px solid #ccc; width: 100%; min-height: 600px;">
Loading PDF...
</div>
@code {
private string documentId = Guid.NewGuid().ToString();
private string ErrorMessage = string.Empty;
private bool pdfLoaded = false;
// Hold the reference to the loaded JavaScript module
private IJSObjectReference? jsModule;
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender && !pdfLoaded)
{
try
{
// 1. Asynchronously load the JavaScript file as a module
// This guarantees the script is loaded before the next line executes.
jsModule = await JSRuntime.InvokeAsync<IJSObjectReference>("import",
"./pdfViewerInterop.js");
await LoadPdfWithJavaScript();
pdfLoaded = true;
}
catch (Exception ex)
{
ErrorMessage = $"Failed to load JS module or execute: {ex.Message}";
}
finally
{
StateHasChanged();
}
}
}
private async Task LoadPdfWithJavaScript()
{
if (jsModule is null) return; // Should never happen if the module loads successfully
try
{
var pdfPath = Path.Combine(WebHostEnvironment.WebRootPath, "sample.pdf");
if (!File.Exists(pdfPath))
{
ErrorMessage = $"File not found: {pdfPath}";
return;
}
var pdf = PdfDocument.FromFile(pdfPath);
var stream = new MemoryStream(pdf.BinaryData);
// 2. Invoke the function using the module reference
// Note: We only pass the function name here.
await jsModule.InvokeVoidAsync("displayPdf",
documentId, stream.ToArray());
}
catch (Exception ex)
{
ErrorMessage = $"Failed to load PDF or invoke JS: {ex.Message}";
}
}
// IMPORTANT: Dispose of the module when the component is removed
public async ValueTask DisposeAsync()
{
if (jsModule is not null)
{
await jsModule.DisposeAsync();
}
}
}@page "/pdf-jsinterop"
@rendermode InteractiveServer
@using IronPdf
@inject IJSRuntime JSRuntime
@inject Microsoft.AspNetCore.Hosting.IWebHostEnvironment WebHostEnvironment
<h3>IronPDF JavaScript Interop Viewer</h3>
<p>Displays PDF using JavaScript's Blob/ObjectURL capabilities.</p>
@if (!string.IsNullOrEmpty(ErrorMessage))
{
<div class="alert alert-danger">Error: @ErrorMessage</div>
}
<div id="@documentId" style="border: 1px solid #ccc; width: 100%; min-height: 600px;">
Loading PDF...
</div>
@code {
private string documentId = Guid.NewGuid().ToString();
private string ErrorMessage = string.Empty;
private bool pdfLoaded = false;
// Hold the reference to the loaded JavaScript module
private IJSObjectReference? jsModule;
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender && !pdfLoaded)
{
try
{
// 1. Asynchronously load the JavaScript file as a module
// This guarantees the script is loaded before the next line executes.
jsModule = await JSRuntime.InvokeAsync<IJSObjectReference>("import",
"./pdfViewerInterop.js");
await LoadPdfWithJavaScript();
pdfLoaded = true;
}
catch (Exception ex)
{
ErrorMessage = $"Failed to load JS module or execute: {ex.Message}";
}
finally
{
StateHasChanged();
}
}
}
private async Task LoadPdfWithJavaScript()
{
if (jsModule is null) return; // Should never happen if the module loads successfully
try
{
var pdfPath = Path.Combine(WebHostEnvironment.WebRootPath, "sample.pdf");
if (!File.Exists(pdfPath))
{
ErrorMessage = $"File not found: {pdfPath}";
return;
}
var pdf = PdfDocument.FromFile(pdfPath);
var stream = new MemoryStream(pdf.BinaryData);
// 2. Invoke the function using the module reference
// Note: We only pass the function name here.
await jsModule.InvokeVoidAsync("displayPdf",
documentId, stream.ToArray());
}
catch (Exception ex)
{
ErrorMessage = $"Failed to load PDF or invoke JS: {ex.Message}";
}
}
// IMPORTANT: Dispose of the module when the component is removed
public async ValueTask DisposeAsync()
{
if (jsModule is not null)
{
await jsModule.DisposeAsync();
}
}
}IRON VB CONVERTER ERROR developers@ironsoftware.comAdd this JavaScript function to your JavaScript file in the wwwroot folder:
export function displayPdf(elementId, data) {
// 1. Create a Blob from the byte array data
const blob = new Blob([new Uint8Array(data)],
{ type: 'application/pdf' });
// 2. Create a temporary URL for the Blob
const url = URL.createObjectURL(blob);
// 3. Find the container element
const container = document.getElementById(elementId);
if (!container) return;
// 4. Clear any previous content
container.innerHTML = '';
// 5. Create and configure the iframe
const iframe = document.createElement('iframe');
iframe.src = url;
iframe.style.width = '100%';
iframe.style.height = '600px';
iframe.style.border = 'none';
// 6. Append the iframe to the container
container.appendChild(iframe);
}export function displayPdf(elementId, data) {
// 1. Create a Blob from the byte array data
const blob = new Blob([new Uint8Array(data)],
{ type: 'application/pdf' });
// 2. Create a temporary URL for the Blob
const url = URL.createObjectURL(blob);
// 3. Find the container element
const container = document.getElementById(elementId);
if (!container) return;
// 4. Clear any previous content
container.innerHTML = '';
// 5. Create and configure the iframe
const iframe = document.createElement('iframe');
iframe.src = url;
iframe.style.width = '100%';
iframe.style.height = '600px';
iframe.style.border = 'none';
// 6. Append the iframe to the container
container.appendChild(iframe);
}IRON VB CONVERTER ERROR developers@ironsoftware.comThis JavaScript function creates a blob from the PDF data and generates an object URL. It then creates an iframe element dynamically and appends it to the container. This approach gives you more control over how PDF pages are displayed and allows for better handling of the PDF viewer component's lifecycle.
Output

Loading PDF Files from Different Sources
Your Blazor PDF viewer can retrieve and display PDF documents from various sources:
private async Task LoadFromUrl()
{
var client = new HttpClient();
var response = await client.GetAsync("https://example.com/file.pdf");
var stream = await response.Content.ReadAsStreamAsync();
var pdfDocument = new PdfDocument(stream);
await DisplayPdfContent(pdfDocument);
}
private async Task LoadFromHtmlContent()
{
var renderer = new ChromePdfRenderer();
var htmlContent = "<h1>Generated PDF</h1>";
var pdfDocument = renderer.RenderHtmlAsPdf(htmlContent);
await DisplayPdfContent(pdfDocument);
}
private async Task DisplayPdfContent(PdfDocument document)
{
var data = document.BinaryData;
pdfUrl = $"data:application/pdf;base64,{Convert.ToBase64String(data)}";
}private async Task LoadFromUrl()
{
var client = new HttpClient();
var response = await client.GetAsync("https://example.com/file.pdf");
var stream = await response.Content.ReadAsStreamAsync();
var pdfDocument = new PdfDocument(stream);
await DisplayPdfContent(pdfDocument);
}
private async Task LoadFromHtmlContent()
{
var renderer = new ChromePdfRenderer();
var htmlContent = "<h1>Generated PDF</h1>";
var pdfDocument = renderer.RenderHtmlAsPdf(htmlContent);
await DisplayPdfContent(pdfDocument);
}
private async Task DisplayPdfContent(PdfDocument document)
{
var data = document.BinaryData;
pdfUrl = $"data:application/pdf;base64,{Convert.ToBase64String(data)}";
}IRON VB CONVERTER ERROR developers@ironsoftware.comThese methods demonstrate loading PDF files from URLs using HTTPS, converting HTML content to PDF, and displaying the resulting PDF content. The LoadFromUrl method retrieves PDF documents from remote locations, while LoadFromHtmlContent shows how to convert HTML to PDF on the fly, providing flexibility in how your Blazor PDF viewer component sources its content.
Output using HTML Content

Adding Interactive Features
Enhance your PDF viewer with interactive functionality:
@code {
private int currentPage = 1;
private int totalPages;
private string rotationClass = "";
private async Task NavigateToPage(int page)
{
currentPage = page;
await JSRuntime.InvokeVoidAsync("navigateTo", page);
}
private void RotateCounterclockwise()
{
// Counterclockwise switch orientation
rotationClass = "rotate-270";
}
private async Task PrintPdf()
{
await JSRuntime.InvokeVoidAsync("printDocument", documentId);
}
private async Task DownloadPdf()
{
var fileName = "document.pdf";
await JSRuntime.InvokeVoidAsync("downloadFile",
pdfData, fileName);
}
}@code {
private int currentPage = 1;
private int totalPages;
private string rotationClass = "";
private async Task NavigateToPage(int page)
{
currentPage = page;
await JSRuntime.InvokeVoidAsync("navigateTo", page);
}
private void RotateCounterclockwise()
{
// Counterclockwise switch orientation
rotationClass = "rotate-270";
}
private async Task PrintPdf()
{
await JSRuntime.InvokeVoidAsync("printDocument", documentId);
}
private async Task DownloadPdf()
{
var fileName = "document.pdf";
await JSRuntime.InvokeVoidAsync("downloadFile",
pdfData, fileName);
}
}IRON VB CONVERTER ERROR developers@ironsoftware.comThis code adds navigation between PDF pages, rotation functionality (including counterclockwise switch orientation), and the ability to print PDFs. The download functionality allows users to save PDF files locally. These features transform your basic PDF viewer into a powerful PDF viewer with a built-in toolbar that provides essential functionality for users working with PDF documents.
Output

Handling PDF Form Filling and Annotations
For PDF documents with form fields and annotations, IronPDF provides robust support:
private async Task ProcessFormFields(
{
var pdfDocument = PdfDocument.FromFile("form.pdf");
foreach (var field in pdfDocument.Form.Fields)
{
if (field.Type == PdfFormFieldType.Text)
{
field.Value = "User Input";
}
}
// Enable form filling in viewer
var modifiedPdf = pdfDocument.BinaryData;
await DisplayPdfContent(pdfDocument);
}private async Task ProcessFormFields(
{
var pdfDocument = PdfDocument.FromFile("form.pdf");
foreach (var field in pdfDocument.Form.Fields)
{
if (field.Type == PdfFormFieldType.Text)
{
field.Value = "User Input";
}
}
// Enable form filling in viewer
var modifiedPdf = pdfDocument.BinaryData;
await DisplayPdfContent(pdfDocument);
}IRON VB CONVERTER ERROR developers@ironsoftware.comThis enables form filling capabilities within your Blazor PDF viewer component, allowing users to interact with form fields directly in the browser. The code iterates through form fields in the PDF document and can programmatically set values, making it ideal for applications requiring dynamic form filling.
Output

Performance Optimization
To ensure high performance when displaying PDFs, especially for large PDF files:
private async Task LoadLargePdf()
{
const int chunkSize = 1024 * 1024; // 1MB chunks
var pdfPath = "largefile.pdf";
using (var fileStream = File.OpenRead(pdfPath))
{
var buffer = new byte[chunkSize];
var chunks = new List<byte[]>();
int bytesRead;
while ((bytesRead = await fileStream.ReadAsync(buffer)) > 0)
{
var chunk = new byte[bytesRead];
Array.Copy(buffer, chunk, bytesRead);
chunks.Add(chunk);
}
// Process chunks for display
await ProcessPdfChunks(chunks);
}
}private async Task LoadLargePdf()
{
const int chunkSize = 1024 * 1024; // 1MB chunks
var pdfPath = "largefile.pdf";
using (var fileStream = File.OpenRead(pdfPath))
{
var buffer = new byte[chunkSize];
var chunks = new List<byte[]>();
int bytesRead;
while ((bytesRead = await fileStream.ReadAsync(buffer)) > 0)
{
var chunk = new byte[bytesRead];
Array.Copy(buffer, chunk, bytesRead);
chunks.Add(chunk);
}
// Process chunks for display
await ProcessPdfChunks(chunks);
}
}IRON VB CONVERTER ERROR developers@ironsoftware.comThis approach loads large PDF files in chunks, preventing memory issues and ensuring smooth performance even with substantial PDF documents. It's particularly useful when dealing with PDF files on mobile phones or devices with limited resources.
Security Considerations for Your Blazor Application
When working with password-protected PDF files:
private async Task LoadSecurePdf(string password)
{
var pdfDocument = PdfDocument.FromFile("secure.pdf", password);
if (pdfDocument != null)
{
var headers = new Dictionary<string, string>
{
{"X-Frame-Options", "SAMEORIGIN"},
{"Content-Security-Policy", "default-src 'self'"}
};
await DisplayPdfContent(pdfDocument);
}
}private async Task LoadSecurePdf(string password)
{
var pdfDocument = PdfDocument.FromFile("secure.pdf", password);
if (pdfDocument != null)
{
var headers = new Dictionary<string, string>
{
{"X-Frame-Options", "SAMEORIGIN"},
{"Content-Security-Policy", "default-src 'self'"}
};
await DisplayPdfContent(pdfDocument);
}
}IRON VB CONVERTER ERROR developers@ironsoftware.comThis code demonstrates loading password-protected PDF documents while maintaining security through proper headers configuration.
Conclusion
Implementing a Blazor PDF viewer with IronPDF provides developers with a comprehensive solution for displaying PDFs in web applications. From basic display to advanced features like form filling and annotations, IronPDF's PDF viewer component offers the functionality needed for professional applications.
The examples shown demonstrate how to create a robust Blazor PDF viewer that can handle various PDF sources, provide interactive features, and maintain high performance. Whether you're building a simple document viewer or a complex document management system, IronPDF's integration with Blazor Server apps makes it easy to implement professional PDF viewing capabilities.
Ready to implement your own PDF viewer? Start your free trial of IronPDF today and access complete documentation, demo applications, and developer support to create powerful PDF viewing experiences in your Blazor applications.







