Build forms in HTML. Style them with CSS. Collect data with JavaScript.
Generate a document from your own web form, or use the isolated JavaScript mode in pasteToPrint for interactive calculations. Review the result, draw on the page, add shapes or images, then print or export PDF.
Declared developer environment
Three web layers. One printable result.
Use JavaScript in your host application or in the editor’s isolated JavaScript mode. The editor keeps script source separately and produces a sanitized static document for printing.
HTML
Structure the printable form
Use semantic sections, headings, fields rendered as text, lists, tables, links and safe images to define the document.
CSS
Control the visual layout
Preserve colors, typography, spacing, borders, dimensions, flex, grid and page breaks through safe CSS inlining.
JavaScript
Collect data and calculate results
On your website, validate forms and collect values with FormData. In the editor, use the supported virtual DOM and events for calculations and document updates.
Host application workflow
From live form to reviewed document.
The example below runs on your own website and imports a static summary. Alternatively, import HTML with embedded scripts and explicitly start them in the editor’s JavaScript mode.
-
01
Design the host form
Create standard inputs, selects and validation rules in your own application.
-
02
Collect and validate
Validate the form before importing. FormData collects values; it does not perform validation. Validate requests again on your backend.
-
03
Generate HTML and CSS
Escape user values and map them into a printable semantic document.
-
04
Hand off for review
Send the summary through the SDK. The user can review, edit, draw, print or export PDF. Optional email scheduling is handled separately by your backend.
Support contract
A clear boundary for every layer.
Distinguish the host website, the isolated JavaScript editor and the static print output. Each environment supports different capabilities.
FormData · DOM · input · change · click · keydown · keyup · focus · blur · submit
Embedded classic scripts and selected inline event handlers are imported into separate script source. They run only after the user presses Run; printed pages and PDF contain the static result.
Host example with optional backend integration
Validate, escape, generate, import.
Run this example on your own website. It imports a static summary through the SDK. Email scheduling requires your own authenticated endpoint and queue; it sends the original summary after import is accepted, without waiting for subsequent editor changes.
<form id="inspectionForm">
<label>
Customer
<input name="customer" required>
</label>
<label>
Device
<input name="device" required>
</label>
<label>
Result
<select name="result" required>
<option value="Passed">Passed</option>
<option value="Defect found">Defect found</option>
</select>
</label>
<label>
<input type="checkbox" name="emailEnabled" value="yes">
Send the result to my email
</label>
<label>
Email
<input name="email" type="email" autocomplete="email">
</label>
<label>
Send after (minutes)
<input name="delayMinutes" type="number"
min="0" max="10080" value="60">
</label>
<button type="submit" data-pastetoprint-button>
Create printable report
</button>
</form>
<p id="formStatus" role="status" aria-live="polite"></p>
<script src="https://www.pastetoprint.com/assets/js/import-button.js?v=1.5.0"></script>
<script>
const escapeHtml = (value) => String(value).replace(
/[&<>"']/g,
(character) => ({
'&': '&',
'<': '<',
'>': '>',
'"': '"',
"'": '''
})[character]
);
const form = document.getElementById('inspectionForm');
const status = document.getElementById('formStatus');
const submitButton = form.querySelector('button[type="submit"]');
const emailEnabled = form.elements.namedItem('emailEnabled');
const emailField = form.elements.namedItem('email');
const delayField = form.elements.namedItem('delayMinutes');
function syncEmailFields() {
for (const field of [emailField, delayField]) {
field.disabled = !emailEnabled.checked;
field.required = emailEnabled.checked;
}
}
emailEnabled.addEventListener('change', syncEmailFields);
syncEmailFields();
form.addEventListener('submit', async (event) => {
event.preventDefault();
if (submitButton.disabled || !form.reportValidity()) return;
status.textContent = '';
submitButton.disabled = true;
let importAccepted = false;
try {
// Names are unique here. Use FormData.getAll(name) for repeated fields.
// Disabled fields and unchecked checkboxes are omitted by FormData.
const data = Object.fromEntries(new FormData(event.currentTarget));
const html = `
<article class="report">
<header>
<span>INSPECTION REPORT</span>
<h1>${escapeHtml(data.device)}</h1>
</header>
<section class="details">
<p><small>Customer</small>
<strong>${escapeHtml(data.customer)}</strong></p>
<p><small>Result</small>
<strong>${escapeHtml(data.result)}</strong></p>
</section>
</article>`;
const css = `
.report {
padding: 18mm;
border: 1px solid #cbd5e1;
font-family: Arial;
}
.report header {
padding: 18px;
background: #173f8a;
color: #ffffff;
}
.details {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 12px;
margin-top: 18px;
}
.details p {
padding: 12px;
border: 1px solid #cbd5e1;
}
.details small,
.details strong {
display: block;
}`;
const title = `Inspection – ${data.device}`;
await PasteToPrint.import({
title,
mode: 'replace',
items: [{ kind: 'html', html, css }]
});
importAccepted = true;
if (data.emailEnabled === 'yes') {
const delayMinutes = Math.min(
10080,
Math.max(0, Number(data.delayMinutes) || 0)
);
const sendAt = new Date(
Date.now() + delayMinutes * 60_000
).toISOString();
// Implement this authenticated endpoint in your host backend.
// Validate the recipient, delay and content again on the server.
// Add a persistent queue to send even after the tab is closed.
// This sends the ORIGINAL summary, not later changes in the editor.
// Import acceptance does not mean editing or printing is complete.
const response = await fetch('/api/form-deliveries', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
recipient: data.email,
sendAt,
formData: {
customer: data.customer,
device: data.device,
result: data.result
},
document: { title, html, css }
})
});
if (!response.ok) {
throw new Error('Email delivery could not be scheduled.');
}
}
status.textContent = data.emailEnabled === 'yes'
? 'Report imported and original summary scheduled for email.'
: 'Report imported. Continue reviewing it in pasteToPrint.';
} catch (error) {
status.textContent = (importAccepted
? 'Report imported, but email scheduling failed: '
: 'Import failed: ') + error.message;
} finally {
submitButton.disabled = false;
}
});
</script>
Repair and security
Tolerant input. Strict document boundary.
Common authoring mistakes are repaired where possible. Script execution requires an explicit user action in the isolated JavaScript mode; the print output is sanitized separately.
Automatic recovery
The browser repairs missing closing HTML tags and tolerates a missing final CSS semicolon or brace. Unreadable declarations are discarded individually.
Separate script source and static output
Classic embedded scripts are stored separately, and supported inline handlers become event listeners. External scripts, module scripts and unsupported handlers are skipped. The static print output excludes executable code; unsafe embeds and CSS are filtered.
Review before output
Send only data needed for the result. Obtain consent, verify the recipient and let the user cancel or reschedule a pending email.
Choose the smallest safe handoff
Use browser IMPORT for user-triggered HTML/CSS. Use PTDF Public Sessions or Document API v2 when the backend already has structured document data.
Turn your next web form into a printable workflow.
Use JavaScript on your website or in the isolated editor, review the static HTML/CSS result and print or export PDF. Implement any scheduled email delivery in your own backend.