How to Open a PDF in a New Tab in Blazor
Opening PDF documents in a new browser tab is a common requirement for Blazor web applications. This tutorial demonstrates how to generate PDFs using IronPDF and display them in new tabs using JavaScript interop, providing users with a seamless document viewing experience. This example focuses on a Blazor Server version.
Prerequisites and Setup
Start by creating a new Blazor Server project in Visual Studio 2022. Install IronPDF via the NuGet Package Manager Console:
Install-Package IronPdf
Configure your IronPDF license in Program.cs to enable full functionality:
License.LicenseKey = "YOUR-LICENSE-KEY";License.LicenseKey = "YOUR-LICENSE-KEY";IRON VB CONVERTER ERROR developers@ironsoftware.comUnderstanding the Challenge
Blazor Server applications can't directly manipulate browser tabs from C# code on the server. The task of Blazor open PDF in a new tab requires JavaScript Interop (JS interop) to bridge server-side PDF generation with client-side window management.
IronPDF enables developers to generate high-quality PDF documents on the server, which can then be displayed using JavaScript's window.open() functionality. This approach means solving a common client-server problem in a .NET application.
Implementing JavaScript Functions in Your Blazor Web App
Add this JavaScript code to your _Host.cshtml file to handle PDF display in new browser tabs. This is the module responsible for client-side window management:
<script>
window.openPdfInNewTab = function (pdfData, fileName) {
// Convert base64 to blob
const byteCharacters = atob(pdfData);
const byteNumbers = new Array(byteCharacters.length);
for (let i = 0; i < byteCharacters.length; i++) {
byteNumbers[i] = byteCharacters.charCodeAt(i);
}
const byteArray = new Uint8Array(byteNumbers);
// The type is 'application/pdf', not 'image/png' or 'image/jpg'
const blob = new Blob([byteArray], { type: 'application/pdf' });
// Create URL and open in new tab
const blobUrl = URL.createObjectURL(blob);
const newWindow = window.open(blobUrl, '_blank');
if (newWindow) {
newWindow.document.title = fileName || 'PDF Document';
}
// Clean up
setTimeout(() => URL.revokeObjectURL(blobUrl), 100);
return newWindow !== null;
};
</script><script>
window.openPdfInNewTab = function (pdfData, fileName) {
// Convert base64 to blob
const byteCharacters = atob(pdfData);
const byteNumbers = new Array(byteCharacters.length);
for (let i = 0; i < byteCharacters.length; i++) {
byteNumbers[i] = byteCharacters.charCodeAt(i);
}
const byteArray = new Uint8Array(byteNumbers);
// The type is 'application/pdf', not 'image/png' or 'image/jpg'
const blob = new Blob([byteArray], { type: 'application/pdf' });
// Create URL and open in new tab
const blobUrl = URL.createObjectURL(blob);
const newWindow = window.open(blobUrl, '_blank');
if (newWindow) {
newWindow.document.title = fileName || 'PDF Document';
}
// Clean up
setTimeout(() => URL.revokeObjectURL(blobUrl), 100);
return newWindow !== null;
};
</script>The window.openPdfInNewTab JavaScript function is crucial for solving the challenge of opening a new tab from the server. It accepts the PDF data as a Base64 string from the Blazor server, and client-side code converts it into a binary Blob object.
This blob is then used to create a temporary URL, which is finally passed to window.open(blobUrl, '_blank') to force the browser to open the PDF in a new tab.
Creating the Blazor Component
Create a new Razor component that generates PDFs and opens them in new tabs. This serves as the main template for the solution:
@page "/pdf-viewer"
@using IronPdf
@inject IJSRuntime JS
<h3>Open PDF in New Tab</h3>
<div class="mb-3">
<label>Enter URL:</label>
</div>
<button class="btn btn-primary" @onclick="GenerateAndOpenPdf" disabled="@isProcessing">
@if (isProcessing)
{
<span>Generating PDF...</span>
}
else
{
<span>Generate and Open PDF</span>
}
</button>
@if (!string.IsNullOrEmpty(errorMessage))
{
<div class="alert alert-danger mt-3">@errorMessage</div>
}
@code {
private string targetUrl = "https://ironpdf.com";
private bool isProcessing = false;
private string errorMessage = "";
private async Task GenerateAndOpenPdf()
{
isProcessing = true;
errorMessage = "";
try
{
// Configure Chrome PDF renderer. Note the rendering details
var renderer = new ChromePdfRenderer
{
RenderingOptions = new ChromePdfRenderOptions
{
MarginTop = 10,
MarginBottom = 10,
MarginLeft = 10,
MarginRight = 10,
EnableJavaScript = true,
RenderDelay = 500
}
};
// Generate PDF from URL
var pdfDocument = await Task.Run(() =>
renderer.RenderUrlAsPdf(targetUrl));
// Convert to base64
byte[] pdfBytes = pdfDocument.BinaryData;
string base64Pdf = Convert.ToBase64String(pdfBytes);
// Open in new tab via JS interop
bool success = await JS.InvokeAsync<bool>("openPdfInNewTab",
base64Pdf, $"Document_{DateTime.Now:yyyyMMdd_HHmmss}.pdf");
if (!success)
{
// Giving the user an understandable error is key
errorMessage = "Pop-up blocked. Please allow pop-ups for this site.";
}
}
catch (Exception ex)
{
errorMessage = $"Error: {ex.Message}";
}
finally
{
isProcessing = false;
}
}
}This code block defines the main interactive page. The Razor markup creates a simple user interface with a URL input field and a button. The C# @code block handles the logic: when the button is clicked, it uses a ChromePdfRenderer instance to generate the PDF from the user's provided URL.
It then converts the resulting PDF byte array into a Base64 string and uses @inject IJSRuntime JS to call the JavaScript function, opening the document for the user.
UI Output

Output with PDF Opened in New Tab

Working with Dynamic HTML Content
For generating PDFs from dynamic content instead of URLs, modify your approach to use RenderHtmlAsPdf:
private async Task GenerateFromHtml()
{
// Define CSS styles inside the HTML string for structure and appearance.
string htmlContent = $@"
<!DOCTYPE html>
<html>
<head>
<style>
body {{ font-family: Arial; padding: 20px; }}
h1 {{ color: #2c3e50; }}
</style>
</head>
<body>
<h1>{documentTitle}</h1>
<p>{documentContent}</p>
<div>Generated: {DateTime.Now}</div>
</body>
</html>";
var renderer = new ChromePdfRenderer();
var pdfDocument = renderer.RenderHtmlAsPdf(htmlContent);
byte[] pdfBytes = pdfDocument.BinaryData;
await JS.InvokeVoidAsync("openPdfInNewTab",
Convert.ToBase64String(pdfBytes), "dynamic.pdf");
}private async Task GenerateFromHtml()
{
// Define CSS styles inside the HTML string for structure and appearance.
string htmlContent = $@"
<!DOCTYPE html>
<html>
<head>
<style>
body {{ font-family: Arial; padding: 20px; }}
h1 {{ color: #2c3e50; }}
</style>
</head>
<body>
<h1>{documentTitle}</h1>
<p>{documentContent}</p>
<div>Generated: {DateTime.Now}</div>
</body>
</html>";
var renderer = new ChromePdfRenderer();
var pdfDocument = renderer.RenderHtmlAsPdf(htmlContent);
byte[] pdfBytes = pdfDocument.BinaryData;
await JS.InvokeVoidAsync("openPdfInNewTab",
Convert.ToBase64String(pdfBytes), "dynamic.pdf");
}IRON VB CONVERTER ERROR developers@ironsoftware.comThe GenerateFromHtml method demonstrates how IronPDF can generate a PDF from dynamically generated HTML markup instead of an existing URL. It constructs a full HTML string containing a heading, content, and dynamic data. The answer to dynamic content generation is the RenderHtmlAsPdf method.
Updated Blazor Server UI

PDF Opened in New Browser Tab

Handling Common Issues
Cross-Browser Compatibility
Different browsers handle blob URLs differently. Test your implementation across Chrome, Firefox, Edge, and Safari to ensure consistent behavior.
Large Files
For large PDF documents, consider implementing server-side caching to improve performance:
services.AddMemoryCache();
// Cache generated PDFs to avoid regenerationservices.AddMemoryCache();
// Cache generated PDFs to avoid regenerationIRON VB CONVERTER ERROR developers@ironsoftware.comNavigation Alternatives
Besides JavaScript interop, you can serve PDFs through static file middleware and use standard HTML anchor tags for an alternative navigation option:
<a href="/pdfs/document.pdf" target="_blank">Open PDF</a><a href="/pdfs/document.pdf" target="_blank">Open PDF</a>This approach works well for pre-generated PDFs but lacks the dynamic generation capabilities of the JS Interop method.
Best Practices
- Error Handling: Always wrap PDF generation in
try-catchblocks and provide meaningful error messages to users when a problem occurs. - Performance: Use
async/awaitpatterns to prevent UI blocking during PDF generation. - User Experience: Show loading indicators during generation and handle pop-up blocker scenarios gracefully.
- DOM Manipulation: Remember that C# on the server cannot manipulate the client's DOM directly; this is why JS Interop is essential. You don't need to manually set the height or width of the new window, as the browser handles the PDF viewer.
- Security: Validate and sanitize user input before generating PDFs.
Conclusion
Combining IronPDF's powerful PDF generation capabilities with Blazor's JavaScript Interop provides a robust solution for opening PDFs in new browser tabs. This approach enables developers to create dynamic, professional PDF documents that seamlessly integrate with modern Blazor applications built on .NET technology by Microsoft.
Ready to implement PDF functionality in your Blazor project? Start your free IronPDF trial today. The trial includes full functionality without watermarks and comprehensive support to ensure your success.







