IRONSOFTWAREHOME

How to Convert HTML Elements and Partial Page Sections to PDF in C#

Curtis Chau
Curtis Chau
Updated: March 11, 2026

IronPDF does not expose a built-in SelectElement or SelectCss method for targeting specific HTML elements. The ChromePdfRenderer renders complete HTML documents - a full page, a full URL, a full HTML string. To produce a PDF from a specific section of a page, we isolate the target element before rendering using one of four approaches: JavaScript DOM manipulation, CSS injection, server-side HTML fragment extraction, or URL rendering with JS targeting.

Each approach suits a different constraint. JavaScript DOM isolation works when rendering URLs or full pages where we need to strip everything except the target. CSS injection hides unwanted content without altering the DOM. Server-side extraction provides the cleanest result when we have access to the raw HTML. URL rendering with JS targeting handles live dashboards and third-party pages where the source HTML is not available.

Start a free 30-day trial to test all four approaches.

Quickstart: Extract a Specific HTML Element as PDF

Target any element by CSS selector using JavaScript DOM isolation and WaitFor, then render only that fragment to PDF.

  1. 1Install IronPDF with NuGet Package Manager

    PM > Install-Package IronPdf

  2. 2Copy and run this code snippet.

    using IronPdf;
    
    var renderer = new ChromePdfRenderer();
    renderer.RenderingOptions.EnableJavaScript = true;
    renderer.RenderingOptions.Javascript = @"
        var target = document.querySelector('#invoice-summary');
        document.body.innerHTML = target.outerHTML;
    ";
    renderer.RenderingOptions.WaitFor.HtmlQuerySelector("#invoice-summary", 10000);
    
    var pdf = renderer.RenderHtmlAsPdf(fullPageHtml);
    pdf.SaveAs("invoice-summary.pdf");
    C#
  3. 3Deploy to test on your live environment

    Start using IronPDF in your project today with a free trial
    arrow pointer

Minimal Workflow (3 Steps)

  1. Install IronPdf via NuGet: Install-Package IronPdf
  2. Configure ChromePdfRenderOptions.Javascript to isolate the target element and WaitFor to ensure it exists
  3. Call RenderHtmlAsPdf() or RenderUrlAsPdf() - the PDF contains only the isolated content

How to Isolate Elements with JavaScript DOM Manipulation?

The ChromePdfRenderOptions.Javascript property accepts a string of JavaScript that executes after the HTML loads but before the PDF renders. By replacing document.body.innerHTML with the outerHTML of the target element, we strip everything else from the rendered page. This is the most versatile approach - it works with both RenderHtmlAsPdf() and RenderUrlAsPdf().

The WaitFor.HtmlQuerySelector() method ensures the target element exists in the DOM before the JavaScript runs. This is critical for pages with asynchronous content - React components, Angular templates, or API-driven data that populates after the initial page load.

using IronPdf;

string fullPageHtml = @"
<html>
<body>
    <header><h1>Acme Corp Invoice</h1></header>
    <nav>Navigation links...</nav>
    <div id='invoice-summary'>
        <h2>Invoice #12345</h2>
        <table>
            <tr><td>Widget A</td><td>$49.99</td></tr>
            <tr><td>Widget B</td><td>$29.99</td></tr>
            <tr><td><strong>Total</strong></td><td><strong>$79.98</strong></td></tr>
        </table>
    </div>
    <footer>Footer content...</footer>
</body>
</html>";

var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.EnableJavaScript = true;

// Replace the body with only the target element
renderer.RenderingOptions.Javascript = @"
    var el = document.querySelector('#invoice-summary');
    if (el) {
        document.body.innerHTML = el.outerHTML;
    }
";

// Wait for the target element to exist before JS executes
renderer.RenderingOptions.WaitFor.HtmlQuerySelector("#invoice-summary", 10000);

PdfDocument pdf = renderer.RenderHtmlAsPdf(fullPageHtml);
pdf.SaveAs("invoice-summary-only.pdf");

The JavaScript replaces the entire body with the #invoice-summary div's outerHTML. The resulting PDF contains only the invoice table - no header, no navigation, no footer. The WaitFor.HtmlElementById() method provides a simpler alternative when targeting by ID:

// Alternative: wait by ID directly
renderer.RenderingOptions.WaitFor.HtmlElementById("invoice-summary", 10000);

For complex selectors (class names, data attributes, nested elements), HtmlQuerySelector() accepts any valid CSS selector string that document.querySelector() would accept. Additional WaitFor convenience methods include HtmlElementByClassName(), HtmlElementByName(), and HtmlElementByTagName() - each internally delegates to HtmlQuerySelector() but provides clearer intent in the code.

When the target element depends on inherited styles from parent containers, the outerHTML replacement can lose CSS rules that rely on ancestor selectors (e.g., .dashboard .widget table { ... }). To preserve these, copy the relevant <style> and <link> tags from the <head> into the JS isolation:

renderer.RenderingOptions.Javascript = @"
    var el = document.querySelector('#invoice-summary');
    if (el) {
        var head = document.head.innerHTML;
        document.body.innerHTML = el.outerHTML;
        document.head.innerHTML = head;
    }
";

This retains the original <head> content (stylesheets, fonts, meta tags) while replacing only the body. The JavaScript to PDF how-to and the WaitFor how-to cover additional configuration options including NetworkIdle0() for pages with multiple async data sources.

How to Isolate Elements with CSS Injection?

The ChromePdfRenderOptions.CustomCssUrl property accepts a file path or URL to a stylesheet that IronPDF applies before rendering. Instead of manipulating the DOM, we hide everything except the target element using CSS display: none. This preserves the original DOM structure and avoids JavaScript execution entirely.

using IronPdf;

// Create a CSS file that hides everything except #invoice-summary
string cssContent = @"
body > *:not(#invoice-summary) {
    display: none !important;
}
#invoice-summary {
    display: block !important;
    margin: 0;
    padding: 20px;
}
";
File.WriteAllText("isolate-element.css", cssContent);

var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.CustomCssUrl = "isolate-element.css";

PdfDocument pdf = renderer.RenderHtmlAsPdf(fullPageHtml);
pdf.SaveAs("invoice-css-isolated.pdf");

Note: The CustomCssUrl property only works with RenderHtmlAsPdf() when rendering from HTML strings. For URL rendering, embed the CSS injection into the Javascript property instead:

renderer.RenderingOptions.Javascript = @"
    var style = document.createElement('style');
    style.textContent = 'body > *:not(#invoice-summary) { display: none !important; }';
    document.head.appendChild(style);
";

When we control the source HTML, @media print rules offer the lightest alternative — no external dependencies, no runtime injection:

@media print {
    header, nav, footer, .sidebar { display: none !important; }
    #invoice-summary { width: 100%; margin: 0; }
}
Text

Set CssMediaType to PdfCssMediaType.Print on the renderer to activate these rules:

renderer.RenderingOptions.CssMediaType = IronPdf.Rendering.PdfCssMediaType.Print;

This is ideal for form section printing scenarios where the application already defines @media print rules, or Approach 3 when the form HTML is assembled server-side.

The CSS approach has one important limitation: hidden elements still occupy space in the document flow if display: none is used at the wrong specificity level. Always use !important to override framework styles (Bootstrap, Tailwind) that might re-display elements at certain breakpoints. For deeply nested targets, a more precise selector avoids collateral hiding:

body > *:not(#target),
body > *:not(#target) ~ * {
    display: none !important;
}
Text

How to Extract HTML Fragments Server-Side?

When we have access to the raw HTML — reading it from a file, a database, a CMS, or an HTTP response — the cleanest approach is to extract the target element server-side using an HTML parser, then pass the fragment to RenderHtmlAsPdf(). No JavaScript, no CSS injection, no runtime DOM manipulation.

AngleSharp is the standard .NET HTML parser for this pattern:

using IronPdf;
using AngleSharp;
using AngleSharp.Html.Parser;

string fullPageHtml = @"
<html>
<head>
    <style>
        table { border-collapse: collapse; width: 100%; }
        td, th { border: 1px solid #ddd; padding: 8px; text-align: left; }
    </style>
</head>
<body>
    <header><h1>Dashboard</h1></header>
    <div id='revenue-widget'>
        <h3>Q4 Revenue</h3>
        <table>
            <tr><th>Month</th><th>Revenue</th></tr>
            <tr><td>October</td><td>$1.2M</td></tr>
            <tr><td>November</td><td>$1.5M</td></tr>
            <tr><td>December</td><td>$1.8M</td></tr>
        </table>
    </div>
    <div id='other-content'>Other widgets...</div>
</body>
</html>";

// Parse and extract the target element
var parser = new HtmlParser();
var document = parser.ParseDocument(fullPageHtml);
var targetElement = document.QuerySelector("#revenue-widget");

if (targetElement is null)
{
    Console.WriteLine("Target element not found.");
    return;
}

// Wrap the fragment in a minimal HTML document to preserve styles
string fragmentHtml = $@"
<html>
<head>
    <style>
        table {{ border-collapse: collapse; width: 100%; }}
        td, th {{ border: 1px solid #ddd; padding: 8px; text-align: left; }}
    </style>
</head>
<body>
    {targetElement.OuterHtml}
</body>
</html>";

var renderer = new ChromePdfRenderer();
PdfDocument pdf = renderer.RenderHtmlAsPdf(fragmentHtml);
pdf.SaveAs("revenue-widget.pdf");

The key detail is wrapping the extracted fragment in a complete HTML document with the relevant <style> or <link> tags. Without this wrapper, inline styles render correctly, but external stylesheets and inherited CSS rules are lost. For email template preview rendering — where the template HTML is already stored as a string — this extraction pattern gives pixel-perfect results because we control every aspect of the rendered content.

The same pattern works with HtmlAgilityPack as an alternative parser:

using HtmlAgilityPack;
using IronPdf;

var htmlDoc = new HtmlDocument();
htmlDoc.LoadHtml(fullPageHtml);

var targetNode = htmlDoc.DocumentNode.SelectSingleNode("//*[@id='revenue-widget']");
if (targetNode is null)
{
    Console.WriteLine("Target element not found.");
    return;
}

string fragmentHtml = $"<html><body>{targetNode.OuterHtml}</body></html>";

var renderer = new ChromePdfRenderer();
PdfDocument pdf = renderer.RenderHtmlAsPdf(fragmentHtml);
pdf.SaveAs("revenue-widget-hap.pdf");
PdfDocument pdf = renderer.RenderHtmlAsPdf(fragmentHtml, @"C:\templates\assets\");

The choice between AngleSharp and HtmlAgilityPack is mostly a preference. AngleSharp uses CSS selectors (QuerySelector), which aligns with frontend developer mental models. HtmlAgilityPack uses XPath (SelectSingleNode), which is more familiar in XML-heavy .NET codebases.

For email template preview rendering — generating a PDF preview of an HTML email template before sending — is a pure Approach 3 scenario. The template HTML is a stored string, external resources (images, fonts) are hosted at known URLs, and the RenderHtmlAsPdf(string Html, string BaseUrlOrPath) parameter on RenderHtmlAsPdf() resolves all relative paths.

When the HTML contains <div id="app"></div> that a React or Vue application populates at runtime, the extracted fragment will be empty. For those cases, use Approach 1 or 4.

My favorite library of this kind is IronPDF. It allows for fast and efficient manipulation of PDF files. It also has many valuable features, like exporting to PDF/A format and digitally signing PDF documents.

Milan Jovanovic

Microsoft MVP

View case study

IronOCR means we can save $40,000 annually from manual processing, while enhancing productivity and freeing up resources for high-impact tasks. I would highly recommend it.

Brent Matzelle

Chief Technology Officer, OPYN

View case study

The IronSuite play a crucial role in our operations. These are tools that increase efficiencies across the business including creating floor plans and improving inventory management.

David Jones

Lead Software Engineer, Agorus Build

View case study

How to Target Elements When Rendering Live URLs?

For live URLs where we cannot access the source HTML — third-party dashboards, external reports, hosted applications — we combine RenderUrlAsPdf() with the Javascript property and WaitFor to isolate a specific section after the page loads.

This is the dashboard widget export scenario: a BI tool renders charts and tables on a web page, and we need to export a single widget as a PDF for stakeholder distribution.

using IronPdf;

var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.EnableJavaScript = true;

// Wait for the dashboard widget to render (async content)
renderer.RenderingOptions.WaitFor.HtmlQuerySelector("[data-widget='revenue-chart']", 15000);

// Isolate the widget after it renders
renderer.RenderingOptions.Javascript = @"
    var widget = document.querySelector('[data-widget=""revenue-chart""]');
    if (widget) {
        // Preserve computed styles by cloning into a clean body
        document.body.innerHTML = '';
        document.body.appendChild(widget);
    }
";

PdfDocument pdf = renderer.RenderUrlAsPdf("https://dashboard.example.com/q4-report");
pdf.SaveAs("revenue-chart-export.pdf");

The WaitFor.HtmlQuerySelector() call ensures the widget exists in the DOM before the JavaScript executes. The 15-second timeout accommodates slower API calls that populate dashboard data. The JavaScript then strips the page down to just the widget.

For pages with complex CSS dependencies, the appendChild approach (moving the node rather than copying its outerHTML) preserves more computed styles because the element retains its position in the CSSOM. The innerHTML replacement approach from Approach 1 is simpler but may lose styles that depend on ancestor selectors.

When the target page requires authentication, configure cookies on the renderer before calling RenderUrlAsPdf():

renderer.RenderingOptions.CustomCookies = new Dictionary<string, string>
{
    { "session_id", "abc123" },
    { "auth_token", "bearer-xyz" }
};

The WaitFor class offers additional wait strategies beyond HtmlQuerySelector(). NetworkIdle0() waits until all network requests complete with zero outstanding connections — useful for dashboards that load data from multiple API endpoints. NetworkIdle2() tolerates up to two outstanding connections, which handles pages with persistent WebSocket connections or long-polling. JavaScript() waits for the page to call window.ironpdf.notifyRender() — the most precise option when we control the target page and can signal render-readiness explicitly after all data loads and animations complete.

For recurring dashboard exports (e.g., nightly PDF generation for stakeholder email distribution), wrap the rendering in a retry loop that catches timeout exceptions. If WaitFor exceeds its maxWaitTime, IronPDF proceeds with rendering whatever content is available — which may be incomplete. Increasing the timeout or switching to NetworkIdle0() typically resolves intermittent failures on slower networks.

Comparison of All Four Approaches

ApproachBest ForRequires Source HTMLJS DependencyComplexity
JavaScript DOM IsolationGeneral-purpose element extraction from any sourceNoYesMedium
CSS InjectionHiding sections without DOM changes; @media print layoutsPartial (CustomCssUrl needs RenderHtmlAsPdf)No (unless injecting via JS for URLs)Low
Server-Side Fragment ExtractionCMS content, stored templates, email previewsYesNoLow–Medium
URL Rendering with JS TargetingLive dashboards, third-party pages, SPA widgetsNoYesMedium–High

Choosing the Right Approach

The decision depends on two factors: whether we have access to the raw HTML, and whether the target content requires JavaScript to render.

Invoice line-item extraction is the most common use case. When the invoice HTML is generated server-side (Razor views, Handlebars templates, stored HTML strings), Approach 3 (server-side extraction) gives the cleanest result with zero runtime overhead. Extract the #line-items table, wrap it in a styled HTML shell, and render.

Dashboard widget export requires JavaScript execution because the widget content is populated by API calls after the initial page load. Approach 1 (JS DOM isolation) handles this when the dashboard runs locally or behind authentication. Approach 4 (URL rendering with JS targeting) is necessary when the dashboard is a third-party hosted application where we only have the URL.

Form section printing — extracting a specific section of a multi-step form for user review or compliance archival — maps naturally to Approach 2 (CSS injection) when the application already defines @media print rules, or Approach 3 when the form HTML is assembled server-side.

Email template preview rendering — generating a PDF preview of an HTML email template before sending — is a pure Approach 3 scenario. The template HTML is a stored string, external resources (images, fonts) are hosted at known URLs, and the BaseUrlOrPath parameter on RenderHtmlAsPdf() resolves all relative paths.

For applications that need to support multiple scenarios, encapsulate the rendering logic behind a service interface that accepts a strategy parameter:

public enum ElementExtractionStrategy
{
    JavaScriptIsolation,
    CssInjection,
    ServerSideExtraction,
    UrlWithJsTargeting
}

This lets the calling code select the appropriate approach based on the input type without duplicating renderer configuration.

Next Steps

HTML element isolation in IronPDF is a rendering-time concern, not a built-in API feature. The four approaches above cover the full spectrum — from server-side template extraction (zero JS, cleanest output) to live URL targeting (full JS execution, handles SPAs and async content). The comparison table provides a quick reference, and the real-world scenarios map common business requirements to the appropriate strategy.

A few additional considerations for production deployments:

Performance: Server-side extraction (Approach 3) is the fastest because it skips JavaScript execution entirely. JavaScript-based approaches (1 and 4) add overhead proportional to the page complexity and the WaitFor timeout. For batch processing (e.g., generating 500 invoice PDFs), server-side extraction with Parallel.ForEach and multiple ChromePdfRenderer instances provides the best throughput.

Debugging: When the PDF output is blank or missing content, enable EnableJavaScript = true and increase the WaitFor timeout. If the target element depends on async data, WaitFor.NetworkIdle0() is more reliable than a fixed RenderDelay. The rendering options guide covers viewport width and paper fit configurations that affect layout.

Combining approaches: Nothing prevents mixing strategies. We can use server-side extraction to build a composite HTML document from multiple fragments (header from one source, data table from another, chart SVG from a third), then render the assembled document as a single PDF. The RenderHtmlAsPdf(string Html, string BaseUrlOrPath) method resolves relative asset paths from the base URL, making it straightforward to compose documents from heterogeneous sources.

Explore the JavaScript to PDF how-to for advanced JS execution patterns, the WaitFor documentation for all available wait strategies, the rendering options guide for the complete ChromePdfRenderOptions surface, and the custom JavaScript code example for ready-to-run snippets.

View licensing options starting at $999. The ChromePdfRenderOptions API reference and WaitFor API reference document every property and method.

Frequently Asked Questions

What is the best approach to convert specific HTML elements to PDF using IronPDF?

IronPDF supports four approaches for converting specific HTML elements to PDF: JavaScript DOM manipulation, CSS injection, server-side HTML fragment extraction, and URL rendering with JavaScript targeting. Each approach fits different scenarios based on access to HTML and JavaScript dependencies.

How can I use JavaScript for PDF generation with IronPDF?

You can use JavaScript DOM manipulation in IronPDF by configuring the `ChromePdfRenderOptions.Javascript` property to isolate the target HTML element before rendering it as a PDF. This is useful for cases where HTML content is populated dynamically via JavaScript frameworks.

Can CSS be used to isolate HTML elements for PDF conversion in IronPDF?

Yes, CSS injection is a method supported by IronPDF to hide unwanted elements by setting `display: none` for everything except the target element. This approach keeps the original DOM structure intact and is efficient when working with server-rendered HTML.

What are the benefits of server-side HTML fragment extraction with IronPDF?

Server-side extraction is beneficial when you have access to source HTML. It allows precise extraction of target elements using HTML parsers like AngleSharp or HtmlAgilityPack, and it renders PDFs without JavaScript, making it fast and clean.

Is it possible to convert live URLs to PDFs targeting specific elements?

Yes, IronPDF allows targeting specific elements from live URLs by using `RenderUrlAsPdf()` with `Javascript` and `WaitFor` options to isolate the desired content after the page loads, useful for third-party hosted content or dashboards.

How can I ensure asynchronous content is rendered in IronPDF?

To ensure asynchronous content is rendered, use the `WaitFor.HtmlQuerySelector()` or methods like `NetworkIdle0()` for waiting strategies. This ensures elements are loaded into the DOM before executing JavaScript for PDF rendering.

What should I consider when choosing an approach for HTML element to PDF conversion?

Consider whether the source HTML is available and whether JavaScript is needed for rendering content. Each approach—JavaScript, CSS, server-side, and URL rendering—has specific scenarios they are best suited for, based on these factors.

How do I maintain CSS styles when isolating HTML elements for PDF?

Preserve CSS styles by copying necessary `