Skip to footer content
USING IRONPDF

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.

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
$vbLabelText   $csharpLabel

How it Works

  1. We create an instance of ChromePdfRenderer, which is the core class for HTML-to-PDF conversion.
  2. The RenderUrlAsPdfAsync method asynchronously fetches the HTML, CSS, and JavaScript from the specified URL and renders it into a PdfDocument object.
  3. The pdf.BinaryData property returns the raw byte array of the generated PDF.
  4. We convert this byte array into a Base64 string and format it as a Data URI.
  5. 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
$vbLabelText   $csharpLabel

Key Customization Features

  • Page Layout: Control properties like PaperSize, Orientation, and margins (MarginTop, MarginBottom, etc.) for precise document layout.
  • Headers and Footers: The TextHeader and TextFooter properties allow you to add text and dynamic fields. You can also use HtmlHeader and HtmlFooter 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 to PdfCssMediaType.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&lt;IResult&gt; DownloadPdf()
{
    var renderer = new ChromePdfRenderer();
    var pdf = await renderer.RenderHtmlAsPdfAsync("&lt;h1&gt;PDF Report&lt;/h1&gt;&lt;p&gt;This is a downloadable PDF generated from a Blazor app.&lt;/p&gt;");

    // 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&lt;IResult&gt; DownloadPdf()
{
    var renderer = new ChromePdfRenderer();
    var pdf = await renderer.RenderHtmlAsPdfAsync("&lt;h1&gt;PDF Report&lt;/h1&gt;&lt;p&gt;This is a downloadable PDF generated from a Blazor app.&lt;/p&gt;");

    // 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("&lt;h1&gt;PDF Report&lt;/h1&gt;&lt;p&gt;This is a downloadable PDF generated from a Blazor app.&lt;/p&gt;")

	' 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
$vbLabelText   $csharpLabel

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();
'}
$vbLabelText   $csharpLabel

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&lt;string, decimal&gt;
    {
        { "IronPDF License", 799m },
        { "Support Package", 299m }
    };

    var html = $@"
        &lt;h1&gt;Invoice #123&lt;/h1&gt;
        &lt;p&gt;Date: {DateTime.Now.ToShortDateString()}&lt;/p&gt;
        &lt;table border='1' width='100%'&gt;
            &lt;thead&gt;
                &lt;tr&gt;&lt;th&gt;Item&lt;/th&gt;&lt;th&gt;Price&lt;/th&gt;&lt;/tr&gt;
            &lt;/thead&gt;
            &lt;tbody&gt;";

    foreach (var item in invoiceData)
    {
        html += $"&lt;tr&gt;&lt;td&gt;{item.Key}&lt;/td&gt;&lt;td&gt;${item.Value}&lt;/td&gt;&lt;/tr&gt;";
    }

    html += "&lt;/tbody&gt;&lt;/table&gt;";

    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&lt;string, decimal&gt;
    {
        { "IronPDF License", 799m },
        { "Support Package", 299m }
    };

    var html = $@"
        &lt;h1&gt;Invoice #123&lt;/h1&gt;
        &lt;p&gt;Date: {DateTime.Now.ToShortDateString()}&lt;/p&gt;
        &lt;table border='1' width='100%'&gt;
            &lt;thead&gt;
                &lt;tr&gt;&lt;th&gt;Item&lt;/th&gt;&lt;th&gt;Price&lt;/th&gt;&lt;/tr&gt;
            &lt;/thead&gt;
            &lt;tbody&gt;";

    foreach (var item in invoiceData)
    {
        html += $"&lt;tr&gt;&lt;td&gt;{item.Key}&lt;/td&gt;&lt;td&gt;${item.Value}&lt;/td&gt;&lt;/tr&gt;";
    }

    html += "&lt;/tbody&gt;&lt;/table&gt;";

    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&gt
'	{
'		{
'			"IronPDF License", 799m
'		}
'	   ,
'		{
'			"Support Package", 299m }
'	};
'
'	var html = string.Format("
'        &lt;h1&gt;Invoice #123&lt;/h1&gt;
'        &lt;p&gt;Date: {0}&lt;/p&gt;
'        &lt;table border='1' width='100%'&gt;
'            &lt;thead&gt;
'                &lt;tr&gt;&lt;th&gt;Item&lt;/th&gt;&lt;th&gt;Price&lt;/th&gt;&lt;/tr&gt;
'            &lt;/thead&gt;
'            &lt;tbody&gt;", DateTime.Now.ToShortDateString());
'
'	foreach (var item in invoiceData)
'	{
'		html += string.Format("&lt;tr&gt;&lt;td&gt;{0}&lt;/td&gt;&lt;td&gt;${1}&lt;/td&gt;&lt;/tr&gt;", item.Key, item.Value);
'	}
'
'	html += "&lt;/tbody&gt;&lt;/table&gt;";
'
'	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));
'}
$vbLabelText   $csharpLabel

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.

Viewing a PDF Generated in a Blazor app in the browser. This PDF has been created by IronPDF and sent to the browser as a base64 string. 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:

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.

First Step:
green arrow pointer

Please note
Aspose and SyncFusion are registered trademarks of their respective owners. This site is not affiliated with, endorsed by, or sponsored by Aspose or SyncFusion. All product names, logos, and brands are the property of their respective owners. Comparisons are provided for informational purposes only and are based on publicly available information at the time of writing.

Frequently Asked Questions

How do I display a PDF in a Blazor component?

You can display a PDF in a Blazor component by generating the PDF document using a library like IronPDF, converting its binary data to a Base64 string, and setting that string as the src for an iframe element. For example: pdfDataUri = $"data:application/pdf;base64,{Convert.ToBase64String(pdf.BinaryData)}";

Can I generate a PDF from a Razor component's HTML?

Yes, you can generate a PDF from a Razor component. The process involves rendering the component to an HTML string first, and then passing that string to IronPDF's RenderHtmlAsPdfAsync method. This allows you to create dynamic, data-driven PDFs using familiar Blazor syntax.

How can I add page numbers to a generated PDF in C#?

To add page numbers, use the ChromePdfRenderOptions class. Set the TextFooter or TextHeader property with special template fields like {page} and {total-pages}. For example: `options.TextFooter.RightText = "Page {page} of {total-pages}";`

What is the best way to let a user download a PDF in a Blazor Server app?

While embedding in an iframe works for viewing, a better download experience is to stream the file. Create an endpoint that returns a FileResult containing the PDF's binary data. This will trigger the browser's native 'Save As' dialog, providing a cleaner user interaction.

Does the .NET PDF library support .NET 9?

Yes, IronPDF is compatible with the latest .NET versions, including .NET 6, 7, 8, and the upcoming .NET 9, ensuring you can use it in modern Blazor applications.

How do I set custom margins or paper size for my PDF?

You can set custom margins and paper size using the ChromePdfRenderOptions object. Set properties like PaperSize = PdfPaperSize.Letter; and MarginTop = 15; (in millimeters) before passing the options object to the render method.

Is it possible to render a web page that uses a lot of JavaScript?

Yes, IronPDF's rendering engine fully supports JavaScript. For pages with complex scripts or animations, you can use the RenderDelay property on ChromePdfRenderOptions to give the JavaScript time to execute before the PDF is captured.

Jacob Mellor, Chief Technology Officer @ Team Iron
Chief Technology Officer

Jacob Mellor is Chief Technology Officer at Iron Software and a visionary engineer pioneering C# PDF technology. As the original developer behind Iron Software's core codebase, he has shaped the company's product architecture since its inception, transforming it alongside CEO Cameron Rimington into a 50+ person company serving NASA, Tesla, and global government agencies.

Jacob holds a First-Class Honours Bachelor of Engineering (BEng) in Civil Engineering from the University of Manchester (1998–2001). After opening his first software business in London in 1999 and creating his first .NET components in 2005, he specialized in solving complex problems across the Microsoft ecosystem.

His flagship IronPDF & IronSuite .NET libraries have achieved over 30 million NuGet installations globally, with his foundational code continuing to power developer tools used worldwide. With 25 years of commercial experience and 41 years of coding expertise, Jacob remains focused on driving innovation in enterprise-grade C#, Java, and Python PDF technologies while mentoring the next generation of technical leaders.