Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

For a webpage you control, the built-in, library-free approach is to prepare a print stylesheet and call window.print(). The browser opens its print dialog, where the user can choose Save as PDF. This works without jsPDF or another PDF library, but it does not return PDF bytes to JavaScript or silently save a file: the user controls the destination and print preferences.

Use the browser’s print-to-PDF workflow

JavaScript’s native window.print() method opens the browser’s print interface for the current document. The page can use print-specific CSS to remove screen controls, set page dimensions and margins where supported, and place deliberate page breaks. The user then selects the browser’s PDF destination. MDN describes window.print() as opening the print dialog to print the current document: MDN: Window.print().

This is a good fit when a person is initiating an export from a page in a regular browser. It is not a way to programmatically serialize arbitrary DOM into a PDF Blob, return PDF bytes from a function, or silently control where a file is saved.

Minimal implementation for the current page

Add a button, print styles and a click handler. This complete example hides controls when printing and requests A4 pages with 16 mm margins:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
<button id="print-button" type="button">Save as PDF</button>

<nav>Site navigation</nav>

<main>
  <h1>Quarterly report</h1>
  <p>This content will appear in the print output.</p>
  <section class="page-break">
    <h2>Next section</h2>
    <p>This section starts after a deliberate page break.</p>
  </section>
</main>

<style>
  @page {
    size: A4;
    margin: 16mm;
  }

  @media print {
    #print-button,
    nav,
    .screen-only {
      display: none !important;
    }

    .page-break {
      break-after: page;
    }
  }
</style>

<script>
  document.querySelector('#print-button').addEventListener('click', () => {
    window.print();
  });
</script>

In a real application, put the script in a module, defer it, or run it after the button exists in the document. The click handler makes the action explicit and user initiated; it also avoids opening the print dialog unexpectedly during page load.

Control the printed layout with CSS

Remove screen-only elements

Place print-specific rules inside @media print. Hide elements that do not belong on paper, such as navigation, action buttons, form controls, floating chat widgets and decorative interface elements. Use display: none !important selectively when application styles would otherwise override the print rule. MDN covers print stylesheets and the beforeprint and afterprint events in its printing guide: MDN: Printing.

Choose paper geometry and margins

Use @page to request a page size such as A4 or letter, orientation such as landscape, and margins. For example:

@page {
  size: letter landscape;
  margin: 12mm;
}

Browser and device support can vary, particularly on older versions. Also, print-dialog settings may take precedence over CSS requests. Treat @page as a layout instruction to validate in the browsers and operating systems your users rely on, not as a guarantee that every user will get identical output. See MDN: @page.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Manage page breaks

For a section that should begin on a new printed page, use modern fragmentation properties such as break-before: page or break-after: page. The legacy page-break-before and page-break-after properties may still be useful when supporting older browser behavior.

@media print {
  .start-new-page {
    break-before: page;
  }

  .keep-together {
    break-inside: avoid;
  }
}

Page breaks are requests to the print layout engine; content size, available page space and browser behavior can affect the final pagination. Check long tables, headings and images for awkward splits in the print preview.

Colors, backgrounds and images

If color is important, test print-color-adjust and inspect the result in the browser’s print preview. Users may have background graphics disabled, and their print preferences can override page styling. Do not assume a background color or image will appear just because it looks correct on screen.

Print a separate HTML document without navigating away

When the content to print is a separate HTML page, a hidden iframe lets the application load it without replacing the current page. Wait for the iframe’s load event before printing; remove the iframe after printing using afterprint or an equivalent cleanup path. This example assumes the URL is accessible to the page and is permitted to be embedded by its response policy:

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
function printSeparatePage(url) {
  const iframe = document.createElement('iframe');
  iframe.src = url;
  iframe.title = 'Document to print';
  iframe.style.position = 'fixed';
  iframe.style.width = '0';
  iframe.style.height = '0';
  iframe.style.border = '0';
  iframe.style.right = '0';
  iframe.style.bottom = '0';

  let cleanedUp = false;
  const cleanup = () => {
    if (cleanedUp) return;
    cleanedUp = true;
    iframe.remove();
  };

  iframe.addEventListener('load', () => {
    const printWindow = iframe.contentWindow;
    if (!printWindow) {
      cleanup();
      return;
    }

    printWindow.addEventListener('afterprint', cleanup, { once: true });
    printWindow.focus();
    printWindow.print();
  }, { once: true });

  iframe.addEventListener('error', cleanup, { once: true });
  document.body.appendChild(iframe);

  // Fallback cleanup for browser environments that do not fire afterprint.
  window.setTimeout(cleanup, 120000);
}

Cross-origin restrictions matter: a page cannot freely inspect or control a document from another origin. A remote site may also prevent framing, so this technique is most reliable for a document your application hosts or otherwise has permission to embed. MDN documents iframe printing and print lifecycle events in its printing guide.

What native printing cannot do

  • Return PDF bytes: window.print() returns undefined; it opens the print interface rather than producing a PDF object for your code.
  • Save silently: ordinary page JavaScript cannot choose a user’s destination, force a filename, or bypass the browser’s print UI.
  • Guarantee settings: the user or browser controls preferences such as paper selection, headers and footers, and whether background graphics are printed.
  • Guarantee identical pagination: browsers, operating systems, fonts, content and print preferences affect layout. Test the actual combinations that matter to your users.

If an application needs automated, repeatable files, batch generation, or programmatic control over output settings, native printing may not meet the requirement. Headless browser automation, a rendering service or a PDF-generation library can address those needs, but each is outside the strict “without a library” browser-print workflow.

Troubleshoot common problems

The print dialog does not open

Call window.print() from a user action such as a click, rather than relying on an automatic call during page load. If printing from an iframe, confirm that it loaded successfully and that the frame is accessible and permitted to be embedded. Browser or device behavior can also differ, so verify the target environment.

The PDF still shows navigation or buttons

Confirm the selectors actually match the unwanted elements and that the rules are inside @media print. If another rule wins the cascade, increase specificity or apply !important to the print-only hiding rule. Check print preview rather than relying on the screen rendering.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Margins, page size or orientation look wrong

Check the @page rule and then inspect the print dialog. User-selected paper and browser settings can override CSS, and some older browser/device combinations may not support every page rule consistently. Test with the same browser and operating system as the intended audience.

Content is cut off or split awkwardly

Use print preview to locate the break, then adjust the relevant layout and apply break-before, break-after or break-inside where appropriate. Recheck tall content and variable-length sections: a break rule cannot make content fit on a page when the content itself exceeds the available space.

Backgrounds or colors are missing

Check the print dialog’s background-graphics preference and test print-color-adjust. The user’s print preferences can override styling, so do not rely on a background as the sole way to communicate important information.

The separate page prints blank

Wait for the iframe’s load event before calling its print method. Confirm the document loaded successfully and can be framed and accessed from the current page; a remote page’s security policy or a cross-origin boundary may prevent this pattern from working.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Or skip the browser setup

If the goal is a PDF capture of a public webpage rather than a user-controlled print flow, ScreenshotNeo provides a screenshot API and MCP server. A request can return an image or PDF; its PDF options include paper size, margins, landscape orientation and page ranges. The API response identifies whether a page was clean, failed or came from cache, and only clean shots are billed. See ScreenshotNeo and the API documentation for current request parameters.

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

The shown request saves an image response; use the documented PDF output option when you need a PDF. This service captures a URL; it is not a browser-side method for turning arbitrary in-memory DOM into PDF bytes. Cookie banners, popups and chat widgets are removed before the shot; bot checks, blank pages and failed loads are never billed; an MCP server lets AI agents take screenshots; 1,000 screenshots a month are free with no card, and paid plans start at $5 for 3,000. Create a free account and try ScreenshotNeo.

Performance, reliability and cost

For an interactive export of a page already open in a browser, printing avoids adding a PDF library to the application, but it depends on the browser and the user completing the print flow. A print stylesheet can simplify the rendered page and make output more legible; it cannot make the process silent or guarantee consistency across devices. If generation must run unattended, produce bytes on a server, or process many pages, choose an approach designed for that workflow and account for its runtime, hosting or service costs.

Frequently Asked Questions

Can JavaScript save the PDF without showing a dialog?

Not with the standard webpage printing API. The browser’s print interface and the user’s destination choice are part of this workflow.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Does window.print() convert a div into a PDF file?

It prints the current document. You can hide unrelated content with print CSS, but it does not return a PDF containing only a DOM element.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.