PDFCrowd Blog
Product updates, tips & tricks

Add a PDF Settings Dialog for Your Website Users with WebSave

When you add a "Save as PDF" button to your website using WebSave, you might want to give visitors control over how their PDF looks. Instead of using fixed settings, you can show a dialog where users choose their preferred page size, filename, and other options before downloading. Learn how to build a custom PDF settings dialog with WebSave.

 

The Key: onBeforeConversion Hook

WebSave provides an onBeforeConversion callback that runs before PDF conversion starts. This callback receives the configuration object and can:

  • Modify settings (like apiSettings or fileName)
  • Return true to cancel the conversion, or false (or nothing) to proceed
  • Return a Promise for async operations (like waiting for user input)

The last point is crucial: by returning a Promise, we can show a dialog, wait for the user's choice, and then either proceed or cancel.

Step 1: Connect the Hook to Your Button

First, set up the button configuration with onBeforeConversion:

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

<script>
  window.myButtonConfig = {
    onBeforeConversion: function(cfg) {
      return showPrintDialog(cfg);
    }
  };
</script>

<button class="pdfcrowd-websave pdfcrowd-websave-style"
        data-key="demo"
        data-config="myButtonConfig">
  Save as PDF
</button>

Step 2: Create the Dialog Logic

The showPrintDialog function returns a Promise. When the user clicks "Download PDF", we modify the config and resolve with false to proceed. When they cancel, we resolve with true to abort:

let printDialog = null;

function showPrintDialog(cfg) {
  return new Promise((resolve) => {
    // Create dialog once, reuse on subsequent calls
    if (!printDialog) {
      printDialog = createPrintDialog();
      document.body.appendChild(printDialog);
    }

    // Show dialog
    printDialog.style.display = 'flex';

    // Handle Download - apply settings and proceed
    document.getElementById('print-download').onclick = () => {
      const pageSize = document.getElementById('print-page-size').value;
      const fileName = document.getElementById('print-filename').value;

      // Modify the config before conversion
      cfg.apiSettings = cfg.apiSettings || {};
      cfg.apiSettings.page_size = pageSize;
      cfg.fileName = fileName;

      printDialog.style.display = 'none';
      resolve(false);  // false = proceed with conversion
    };

    // Handle Cancel
    document.getElementById('print-cancel').onclick = () => {
      printDialog.style.display = 'none';
      resolve(true);  // true = cancel conversion
    };

    // Close on overlay click
    printDialog.onclick = (e) => {
      if (e.target === printDialog) {
        printDialog.style.display = 'none';
        resolve(true);
      }
    };
  });
}

The dialog is created once and reused. This preserves user's previous selections between clicks.

Step 3: Build the Dialog UI

The createPrintDialog function builds a simple form with page size and filename fields:

function createPrintDialog() {
  const overlay = document.createElement('div');
  overlay.className = 'pdf-dialog-overlay';

  overlay.innerHTML = `
    <div class="pdf-dialog">
      <h3>PDF Options</h3>

      <div class="pdf-dialog-field">
        <label>Page Size</label>
        <select id="print-page-size">
          <option value="a4">A4</option>
          <option value="letter">Letter</option>
          <option value="a3">A3</option>
          <option value="a5">A5</option>
        </select>
      </div>

      <div class="pdf-dialog-field">
        <label>File Name</label>
        <input type="text" id="print-filename" value="document.pdf">
      </div>

      <div class="pdf-dialog-buttons">
        <button id="print-download" class="primary">Download PDF</button>
        <button id="print-cancel">Cancel</button>
      </div>
    </div>
  `;

  return overlay;
}

Add some basic CSS to style the overlay and dialog. You can customize these styles to match your website design:

CSS Styles for the Dialog

<style>
  .pdf-dialog-overlay {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: rgba(0,0,0,0.5);
    display: none;
    align-items: center;
    justify-content: center;
    z-index: 10000;
  }
  .pdf-dialog {
    background: white;
    padding: 24px;
    border-radius: 8px;
    min-width: 300px;
    font-family: sans-serif;
  }
  .pdf-dialog h3 {
    margin-top: 0;
  }
  .pdf-dialog-field {
    margin-bottom: 16px;
  }
  .pdf-dialog-field label {
    display: block;
    margin-bottom: 4px;
  }
  .pdf-dialog-field select,
  .pdf-dialog-field input {
    width: 100%;
    padding: 8px;
    box-sizing: border-box;
  }
  .pdf-dialog-buttons {
    text-align: center;
    margin-top: 16px;
  }
  .pdf-dialog-buttons button {
    padding: 8px 16px;
    cursor: pointer;
    border: none;
    border-radius: 4px;
    background: #e7e7e7;
    color: #333;
  }
  .pdf-dialog-buttons .primary {
    background: #4a7cdb;
    color: white;
  }
</style>

Adding More Options

You can easily extend the dialog with additional input fields for orientation, margins, password protection, and more. Just add the HTML elements and read their values into cfg.apiSettings:

// Orientation
cfg.apiSettings.orientation = document.getElementById('print-orientation').value;

// Password protect the PDF
cfg.apiSettings.user_password = document.getElementById('print-password').value;

See the HTML to PDF API Reference for all available options.

Live Demo

Try it yourself:

Here's a complete HTML file you can deploy to your web server:

Complete Working Example

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>PDF Settings Dialog Example</title>
  <script src="https://edge.pdfcrowd.com/websave/1.3.0/websave.min.js" async></script>
  <style>
    .pdf-dialog-overlay {
      position: fixed;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      background: rgba(0,0,0,0.5);
      display: none;
      align-items: center;
      justify-content: center;
      z-index: 10000;
    }
    .pdf-dialog {
      background: white;
      padding: 24px;
      border-radius: 8px;
      min-width: 300px;
      font-family: sans-serif;
    }
    .pdf-dialog h3 {
      margin-top: 0;
    }
    .pdf-dialog-field {
      margin-bottom: 16px;
    }
    .pdf-dialog-field label {
      display: block;
      margin-bottom: 4px;
    }
    .pdf-dialog-field select,
    .pdf-dialog-field input {
      width: 100%;
      padding: 8px;
      box-sizing: border-box;
    }
    .pdf-dialog-buttons {
      text-align: center;
      margin-top: 16px;
    }
    .pdf-dialog-buttons button {
      padding: 8px 16px;
      cursor: pointer;
      border: none;
      border-radius: 4px;
      background: #e7e7e7;
      color: #333;
    }
    .pdf-dialog-buttons .primary {
      background: #4a7cdb;
      color: white;
    }
  </style>
</head>
<body>
  <h1>PDF Settings Dialog Demo</h1>
  <p>Click the button to see the settings dialog.</p>

  <button class="pdfcrowd-websave pdfcrowd-websave-style"
          data-key="demo"
          data-config="myButtonConfig">
    Save as PDF
  </button>

  <script>
    function createPrintDialog() {
      const overlay = document.createElement('div');
      overlay.className = 'pdf-dialog-overlay';

      overlay.innerHTML = `
        <div class="pdf-dialog">
          <h3>PDF Options</h3>

          <div class="pdf-dialog-field">
            <label>Page Size</label>
            <select id="print-page-size">
              <option value="a4">A4</option>
              <option value="letter">Letter</option>
              <option value="a3">A3</option>
              <option value="a5">A5</option>
            </select>
          </div>

          <div class="pdf-dialog-field">
            <label>File Name</label>
            <input type="text" id="print-filename" value="document.pdf">
          </div>

          <div class="pdf-dialog-buttons">
            <button id="print-download" class="primary">Download PDF</button>
            <button id="print-cancel">Cancel</button>
          </div>
        </div>
      `;

      return overlay;
    }

    let printDialog = null;

    function showPrintDialog(cfg) {
      return new Promise((resolve) => {
        if (!printDialog) {
          printDialog = createPrintDialog();
          document.body.appendChild(printDialog);
        }

        printDialog.style.display = 'flex';

        document.getElementById('print-download').onclick = () => {
          const pageSize = document.getElementById('print-page-size').value;
          const fileName = document.getElementById('print-filename').value;

          cfg.apiSettings = cfg.apiSettings || {};
          cfg.apiSettings.page_size = pageSize;
          cfg.fileName = fileName;

          printDialog.style.display = 'none';
          resolve(false);
        };

        document.getElementById('print-cancel').onclick = () => {
          printDialog.style.display = 'none';
          resolve(true);
        };

        printDialog.onclick = (e) => {
          if (e.target === printDialog) {
            printDialog.style.display = 'none';
            resolve(true);
          }
        };
      });
    }

    window.myButtonConfig = {
      onBeforeConversion: function(cfg) {
        return showPrintDialog(cfg);
      }
    };
  </script>
</body>
</html>

Learn More