PDFCrowd Blog
Product updates, tips & tricks

Add PDF Export to Reactive Apps

Users often need to export web pages as PDFs. The browser's window.print() function produces inconsistent results: CSS backgrounds are omitted, page breaks occur mid-element, and layout rendering differs from the screen display.

WebSave as PDF provides a client-side solution for adding PDF export to web applications. It captures the current page state directly in the browser. This guide covers integration for React, Preact, Vue, Angular, Svelte, Astro, and SolidJS.

 

TL;DR

1. Add the script to your HTML file:

<script src="https://edge.pdfcrowd.com/websave/1.3.0/websave.min.js" async></script>

2. Add a button with configuration:

The data-config attribute references a global configuration object:

<button
  class="pdfcrowd-websave pdfcrowd-websave-style"
  data-key="demo"
  data-config="myConfig">
  Download PDF
</button>

<script>
window.myConfig = {
  fileName: 'report.pdf',
  conversionMode: 'content',         // Captures current page state
  apiSettings: {
    page_size: 'Letter'
  }
};
</script>

That's it. The conversionMode: 'content' setting is important for reactive apps - it captures the rendered DOM with all dynamic content, form inputs, and user interactions.

Note for SPAs: If your framework (React, Vue, Svelte, etc.) renders buttons dynamically, you'll need to manually initialize them using window.WebSave.initButton(). See framework-specific examples below for details.

Choose Your Framework

Select your framework to see integration instructions:

React Integration

Loading WebSave

Recommended: Add to index.html in your React project root:

<script src="https://edge.pdfcrowd.com/websave/1.3.0/websave.min.js" async></script>

Next.js: Use Script component in pages/_app.js:

import Script from 'next/script'

export default function MyApp({ Component, pageProps }) {
  return (
    <>
      <Script
        src="https://edge.pdfcrowd.com/websave/1.3.0/websave.min.js"
        strategy="lazyOnload"
      />
      <Component {...pageProps} />
    </>
  )
}

Example

// src/App.jsx
import { useEffect, useRef } from 'react'

function App() {
  const buttonRef = useRef(null);

  useEffect(() => {
    // Configure WebSave with settings
    window.reportConfig = {
      fileName: 'monthly-report.pdf',
      conversionMode: 'content',
      apiSettings: {
        page_size: 'Letter'
      }
    };

    // Initialize the dynamically rendered button
    window.WebSave?.initButton(buttonRef.current);
  }, []);

  return (
    <div>
      <h1>Monthly Report</h1>
      {/* Report content */}

      <button
        ref={buttonRef}
        className="pdfcrowd-websave pdfcrowd-websave-style"
        data-key="demo"
        data-config="reportConfig">
        Download PDF
      </button>
    </div>
  );
}

export default App;

Preact Integration

Loading WebSave

Recommended: Add to src/index.html (Vite) or public/index.html:

<script src="https://edge.pdfcrowd.com/websave/1.3.0/websave.min.js" async></script>

Example

// src/app.jsx
import { useEffect, useRef } from 'preact/hooks'

export function App() {
  const buttonRef = useRef(null);

  useEffect(() => {
    // Configure WebSave with settings
    window.reportConfig = {
      fileName: 'monthly-report.pdf',
      conversionMode: 'content',
      apiSettings: {
        page_size: 'Letter'
      }
    };

    // Initialize the dynamically rendered button
    window.WebSave?.initButton(buttonRef.current);
  }, []);

  return (
    <div>
      <h1>Monthly Report</h1>
      {/* Report content */}

      <button
        ref={buttonRef}
        class="pdfcrowd-websave pdfcrowd-websave-style"
        data-key="demo"
        data-config="reportConfig">
        Download PDF
      </button>
    </div>
  );
}

Vue Integration

Loading WebSave

Recommended: Add to index.html (Vue 3/Vite):

<script src="https://edge.pdfcrowd.com/websave/1.3.0/websave.min.js" async></script>

Nuxt 3: Add to nuxt.config.ts:

export default defineNuxtConfig({
  app: {
    head: {
      script: [
        {
          src: 'https://edge.pdfcrowd.com/websave/1.3.0/websave.min.js',
          async: true
        }
      ]
    }
  }
});

Example

<!-- src/App.vue -->
<script setup>
import { onMounted, ref } from 'vue';

const buttonRef = ref(null);

onMounted(() => {
  // Configure WebSave with settings
  window.reportConfig = {
    fileName: 'monthly-report.pdf',
    conversionMode: 'content',
    apiSettings: {
      page_size: 'Letter'
    }
  };

  // Initialize the dynamically rendered button
  window.WebSave?.initButton(buttonRef.value);
});
</script>

<template>
  <div>
    <h1>Monthly Report</h1>
    <!-- Report content -->

    <button
      ref="buttonRef"
      class="pdfcrowd-websave pdfcrowd-websave-style"
      data-key="demo"
      data-config="reportConfig">
      Download PDF
    </button>
  </div>
</template>

Angular Integration

Loading WebSave

Recommended: Add to src/index.html:

<script src="https://edge.pdfcrowd.com/websave/1.3.0/websave.min.js" async></script>

Example

import { Component, OnInit, AfterViewInit, ElementRef, ViewChild } from '@angular/core';

@Component({
  selector: 'app-report',
  template: `
    <div>
      <h1>Monthly Report</h1>
      <!-- Report content -->

      <button
        #websaveButton
        class="pdfcrowd-websave pdfcrowd-websave-style"
        data-key="demo"
        data-config="reportConfig">
        Download PDF
      </button>
    </div>
  `
})
export class ReportComponent implements OnInit, AfterViewInit {
  @ViewChild('websaveButton') websaveButton!: ElementRef;

  ngOnInit() {
    // Configure WebSave with settings
    (window as any).reportConfig = {
      fileName: 'monthly-report.pdf',
      conversionMode: 'content',
      apiSettings: {
        page_size: 'Letter'
      }
    };
  }

  ngAfterViewInit() {
    // Initialize the dynamically rendered button
    (window as any).WebSave?.initButton(this.websaveButton.nativeElement);
  }
}

Svelte Integration

Loading WebSave

Recommended: Add to public/index.html (Vite) or src/app.html (SvelteKit):

<script src="https://edge.pdfcrowd.com/websave/1.3.0/websave.min.js" async></script>

Example

<!-- src/App.svelte -->
<script>
  import { onMount } from 'svelte';

  let buttonElement;

  onMount(() => {
    // Configure WebSave with settings
    window.reportConfig = {
      fileName: 'monthly-report.pdf',
      conversionMode: 'content',
      apiSettings: {
        page_size: 'Letter'
      }
    };

    // Initialize the dynamically rendered button
    window.WebSave?.initButton(buttonElement);
  });
</script>

<div>
  <h1>Monthly Report</h1>
  <!-- Report content -->

  <button
    bind:this={buttonElement}
    class="pdfcrowd-websave pdfcrowd-websave-style"
    data-key="demo"
    data-config="reportConfig">
    Download PDF
  </button>
</div>

Astro Integration

Loading WebSave

Recommended: Add to your layout file (e.g., src/layouts/Layout.astro):

---
// src/layouts/Layout.astro
---
<html>
  <head>
    <script src="https://edge.pdfcrowd.com/websave/1.3.0/websave.min.js" async></script>
  </head>
  <body>
    <slot />
  </body>
</html>

Alternative: Add to individual pages in the <head> section.

Example

---
// Report.astro
---
<div>
  <h1>Monthly Report</h1>
  <!-- Report content -->

  <button
    class="pdfcrowd-websave pdfcrowd-websave-style"
    data-key="demo"
    data-config="reportConfig">
    Download PDF
  </button>
</div>

<script is:inline>
  // Configure WebSave with settings
  window.reportConfig = {
    fileName: 'monthly-report.pdf',
    conversionMode: 'content',
    apiSettings: {
      page_size: 'Letter'
    }
  };

  // Initialize button after DOM and WebSave are ready
  document.addEventListener('DOMContentLoaded', function() {
    const button = document.querySelector('.pdfcrowd-websave');
    window.WebSave?.initButton(button);
  });
</script>

SolidJS Integration

Loading WebSave

Recommended: Add to index.html:

<script src="https://edge.pdfcrowd.com/websave/1.3.0/websave.min.js" async></script>

Example

// src/App.jsx
import { onMount } from 'solid-js'

function App() {
  let buttonRef;

  onMount(() => {
    // Configure WebSave with settings
    window.reportConfig = {
      fileName: 'monthly-report.pdf',
      conversionMode: 'content',
      apiSettings: {
        page_size: 'Letter'
      }
    };

    // Initialize the dynamically rendered button
    window.WebSave?.initButton(buttonRef);
  });

  return (
    <div>
      <h1>Monthly Report</h1>
      {/* Report content */}

      <button
        ref={buttonRef}
        class="pdfcrowd-websave pdfcrowd-websave-style"
        data-key="demo"
        data-config="reportConfig">
        Download PDF
      </button>
    </div>
  );
}

export default App;

Try It Yourself

Click the button below to export this page as a PDF. WebSave captures the current page state including any text you enter.

Resources