npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

snap-to-pdf

v1.0.1

Published

A lightweight HTML → PDF rendering library for Node + TypeScript

Readme

snap-to-pdf

A lightweight HTML → PDF rendering library for Node.js and TypeScript. Convert HTML to pixel-perfect PDFs with a single function call—no API routes, no fetch requests, just a direct Buffer you can use immediately.

Features

  • One-Function API: Call snapToPdf(html, options) and get a PDF Buffer back instantly
  • No Backend Required: Generate PDFs directly in your server-side code without creating endpoints
  • Professional Styling: Built-in formal document styles or bring your own CSS
  • Layout Control: Smart page breaks, orphan/widow prevention, headers & footers
  • Customization: Themes, custom fonts, watermarks, and debug tools
  • Framework Support: Works seamlessly in Node.js, Next.js, Express, NestJS, and serverless environments

Installation

npm install snap-to-pdf

Core Concept

snap-to-pdf provides a single function that takes HTML and returns a PDF Buffer. You can then:

  • Save it to disk
  • Send it in an HTTP response
  • Trigger a browser download
  • Upload it to cloud storage
  • Use it in any server-side workflow

No API calls required. The library runs entirely server-side and returns the PDF directly.

Quick Start

Node.js

Generate a PDF and save it to disk:

import { snapToPdf } from 'snap-to-pdf';
import { writeFileSync } from 'fs';

const html = '<h1>Invoice #12345</h1><p>Total: $1,234.56</p>';

const pdfBuffer = await snapToPdf(html, { format: 'A4' });

writeFileSync('invoice.pdf', pdfBuffer);

Express / NestJS

Return a PDF directly in an HTTP response:

import { snapToPdf } from 'snap-to-pdf';
import express from 'express';

const app = express();

app.post('/generate-pdf', async (req, res) => {
  const { html } = req.body;
  
  const pdfBuffer = await snapToPdf(html, { format: 'A4' });
  
  res.setHeader('Content-Type', 'application/pdf');
  res.setHeader('Content-Disposition', 'attachment; filename="document.pdf"');
  res.send(pdfBuffer);
});

Next.js (App Router)

The library must run server-side. Use Route Handlers or Server Actions.

Route Handler (Recommended for downloads):

import { snapToPdf } from 'snap-to-pdf';
import { NextRequest } from 'next/server';

export async function POST(request: NextRequest) {
  const { html } = await request.json();
  
  const pdfBuffer = await snapToPdf(html, { format: 'A4' });
  
  return new Response(pdfBuffer, {
    headers: {
      'Content-Type': 'application/pdf',
      'Content-Disposition': 'attachment; filename="document.pdf"',
    },
  });
}

Server Action (Recommended for server-side workflows):

'use server';

import { snapToPdf } from 'snap-to-pdf';
import { writeFileSync } from 'fs';

export async function generateInvoice(invoiceData: InvoiceData) {
  const html = renderInvoiceTemplate(invoiceData);
  
  const pdfBuffer = await snapToPdf(html, { 
    format: 'A4',
    theme: 'standard' 
  });
  
  writeFileSync(`./invoices/${invoiceData.id}.pdf`, pdfBuffer);
  
  return { success: true };
}

Client Component (calls Route Handler):

'use client';

export function DownloadButton({ html }: { html: string }) {
  const handleDownload = async () => {
    const response = await fetch('/api/generate-pdf', {
      method: 'POST',
      body: JSON.stringify({ html }),
    });
    
    const blob = await response.blob();
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = 'document.pdf';
    a.click();
    URL.revokeObjectURL(url);
  };

  return <button onClick={handleDownload}>Download PDF</button>;
}

Serverless (Vercel, AWS Lambda, etc.)

Works in serverless functions—just ensure Puppeteer is available in your runtime:

import { snapToPdf } from 'snap-to-pdf';

export default async function handler(req, res) {
  const { html } = req.body;
  
  const pdfBuffer = await snapToPdf(html, { format: 'A4' });
  
  res.setHeader('Content-Type', 'application/pdf');
  res.send(pdfBuffer);
}

Themes & Styling

snap-to-pdf uses a theme-based system to ensure your PDFs look professional out of the box.

Using Themes

A theme automatically handles:

  • Typography: Professional font stacks and sizing
  • Layout: Print-safe margins and spacing
  • Components: Styled tables, lists, and blockquotes
  • Print Optimization: Smart page breaks and orphan/widow control
// Applies the 'standard' theme by default
const pdf = await snapToPdf(html);

// Choose a specific theme
const pdf = await snapToPdf(html, { theme: 'corporate' });

// Disable theming for raw HTML rendering
const pdf = await snapToPdf(html, { theme: 'none' });

Available Themes

| Theme | Description | |-------|-------------| | standard | Default. Professional formal styling suitable for most documents. Uses Georgia/Times fonts. | | clean | Modern, minimalist look with sans-serif fonts (Helvetica/Arial) and ample whitespace. | | corporate | Business-oriented style with blue accents and serif headers. | | minimal | Bare-bones styling, high contrast, good for data-heavy reports. | | none | No styling injected. You get raw HTML rendering. |

Customizing Styles

Themes provide a solid foundation. You can override any style by including your own CSS in the HTML:

<style>
  /* Override theme font */
  body { font-family: 'Open Sans', sans-serif; }
  /* Custom header color */
  h1 { color: #d32f2f; }
</style>
<h1>Customized Report</h1>

Advanced Usage

Custom Themes, Fonts, and Watermarks

import { snapToPdf, SnapOptions } from 'snap-to-pdf';

const options: SnapOptions = {
  format: 'A4',
  theme: 'corporate',
  watermark: {
    text: 'CONFIDENTIAL',
    color: 'rgba(255, 0, 0, 0.1)',
    opacity: 0.5
  },
  fonts: [
    {
      family: 'Roboto',
      path: './fonts/Roboto-Regular.ttf',
      weight: 400
    }
  ],
  explain: true
};

const pdfBuffer = await snapToPdf('<h1>Report</h1>', options);

Upload to Cloud Storage

import { snapToPdf } from 'snap-to-pdf';
import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3';

const html = '<h1>Monthly Report</h1>';
const pdfBuffer = await snapToPdf(html, { format: 'A4' });

const s3 = new S3Client({ region: 'us-east-1' });
await s3.send(new PutObjectCommand({
  Bucket: 'my-bucket',
  Key: 'reports/monthly.pdf',
  Body: pdfBuffer,
  ContentType: 'application/pdf',
}));

Trigger Browser Download (Server Action)

'use server';

import { snapToPdf } from 'snap-to-pdf';

export async function downloadPdf(html: string) {
  const pdfBuffer = await snapToPdf(html, { format: 'A4' });
  
  return Buffer.from(pdfBuffer).toString('base64');
}
'use client';

import { downloadPdf } from './actions';

export function DownloadButton({ html }: { html: string }) {
  const handleClick = async () => {
    const base64 = await downloadPdf(html);
    
    const binary = atob(base64);
    const bytes = new Uint8Array(binary.length);
    for (let i = 0; i < binary.length; i++) {
      bytes[i] = binary.charCodeAt(i);
    }
    
    const blob = new Blob([bytes], { type: 'application/pdf' });
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = 'document.pdf';
    a.click();
    URL.revokeObjectURL(url);
  };

  return <button onClick={handleClick}>Download PDF</button>;
}

CLI Usage

For quick conversions from the command line:

npx snap-to-pdf input.html -o output.pdf

npx snap-to-pdf report.html --theme corporate --landscape

npx snap-to-pdf input.html --debug

Options:

  • -o, --output <path>: Output PDF file path (default: output.pdf)
  • --format <format>: PDF Format (A4, Letter, etc.) (default: A4)
  • --landscape: Landscape orientation
  • --theme <theme>: Apply a theme (clean, corporate, minimal)
  • --debug: Enable debug mode to visualize layout boundaries

Running Examples

The library includes a fully working example that generates a formal document with a title page, table of contents, and styled sections.

To run the example:

  1. Build the project (if running from source):

    npm run build
  2. Run the example script:

    node examples/generate-formal-document.js

This will create formal-document-output.pdf in the examples directory.

API Reference

snapToPdf(html: string, options?: SnapOptions): Promise<Buffer>

Converts HTML to a PDF Buffer.

Parameters:

  • html: HTML string, file path, or URL
  • options: Configuration object (see below)

Returns: Promise<Buffer> - The generated PDF as a Buffer

SnapOptions

| Option | Type | Description | |--------|------|-------------| | theme | 'standard' \| 'clean' \| 'corporate' \| 'minimal' \| 'none' | Prebuilt theme (default: 'standard'). | | format | string | PDF Format (e.g., 'A4', 'Letter'). | | landscape | boolean | Enable landscape orientation. | | watermark | object | Configuration for text watermarks. | | fonts | array | List of custom fonts to embed. | | debug | boolean | Visual debug overlay. | | explain | boolean | Analyze and log layout issues. | | path | string | Optional: Save PDF to this file path. | | margin | object | Page margins ({ top, right, bottom, left }). | | printBackground | boolean | Print background graphics (default: true). | | displayHeaderFooter | boolean | Show header and footer. | | headerTemplate | string | HTML template for the header. | | footerTemplate | string | HTML template for the footer. |

PDF Configuration Details

Page Formats

Supported formats include:

  • Letter (default in some regions), Legal, Tabloid, Ledger
  • A0, A1, A2, A3, A4 (standard default), A5, A6

Margins

Margins can be configured using the margin option object. Supported units: mm, cm, in, px.

// Example margin configuration
margin: {
  top: '20mm',
  right: '20mm',
  bottom: '20mm',
  left: '20mm'
}

Note: Themes automatically apply optimized margins. Providing a margin option will override the theme's defaults.

Headers & Footers

To display headers and footers, you must:

  1. Set displayHeaderFooter: true
  2. Provide headerTemplate and/or footerTemplate HTML
  3. Ensure margins are large enough to accommodate the content

Variables available in templates:

  • <span class="date"></span>
  • <span class="title"></span>
  • <span class="url"></span>
  • <span class="pageNumber"></span>
  • <span class="totalPages"></span>
headerTemplate: '<div style="font-size: 10px; width: 100%; text-align: center;">Page <span class="pageNumber"></span> of <span class="totalPages"></span></div>'

Environment Detection

The library automatically detects whether it's running in a browser or Node.js environment:

  • Server-side (Node.js, API routes, server actions): Full PDF generation works
  • Client-side (React components, browser): Throws helpful error with guidance

Explicit imports (optional):

import { snapToPdf } from 'snap-to-pdf/node';
import { snapToPdf } from 'snap-to-pdf/browser';

Important Notes

Next.js Usage

snap-to-pdf must run server-side. It cannot run in client components because it requires Node.js and Puppeteer.

✅ DO: Use in Route Handlers, Server Actions, or Server Components
❌ DON'T: Import in Client Components (marked with 'use client')

If you need to trigger PDF generation from a client component, call a Route Handler or Server Action.

Serverless Environments

Ensure Puppeteer is available in your serverless runtime. Some platforms (like Vercel) may require additional configuration or custom layers for Puppeteer support.

License

MIT