Build forms in HTML. Style them with CSS. Collect data with JavaScript.
Use your own web form as the data source, generate a safe printable document, and let the user review it, draw directly on the page, add shapes or image layers, and then print or export PDF in pasteToPrint.
Declared developer environment
Three web layers. One printable result.
Keep the interactive form in your application. pasteToPrint receives only the generated, sanitized document that the user can inspect and edit.
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
Automate data collection
Validate the host form, read values with FormData, calculate results and map them into the HTML document, then optionally schedule email delivery.
Recommended workflow
From live form to reviewed document.
JavaScript performs the automation on the developer’s page. The imported result remains a safe document without executable code.
-
01
Design the host form
Create standard inputs, selects and validation rules in your own application.
-
02
Collect and validate
Use JavaScript and FormData to read values and reject incomplete submissions.
-
03
Generate HTML and CSS
Escape user values and map them into a printable semantic document.
-
04
Hand off for review
Send the result through the SDK; the user reviews it, draws on it or adds shapes and image layers, then prints, exports or schedules delivery.
Support contract
A clear boundary for every layer.
The host application may be fully interactive. The document boundary accepts only presentation-safe HTML and CSS.
Complete host example
Collect, sanitize, generate, import.
This example keeps the live input controls on the host page, sends a safe summary to pasteToPrint and can schedule an email through the host backend.
<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>
<script src="https://www.pastetoprint.com/assets/js/import-button.js?v=1.4.0"></script>
<script>
const escapeHtml = (value) => String(value).replace(
/[&<>"']/g,
(character) => ({
'&': '&',
'<': '<',
'>': '>',
'"': '"',
"'": '''
})[character]
);
document
.getElementById('inspectionForm')
.addEventListener('submit', async (event) => {
event.preventDefault();
if (!event.currentTarget.reportValidity()) return;
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 }]
});
if (data.emailEnabled === 'yes') {
if (!data.email) {
throw new Error('Enter an email address.');
}
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.
// A server-side queue is reliable even after the tab is closed.
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.');
}
}
});
</script>
Repair and security
Tolerant input. Strict document boundary.
Common authoring mistakes are repaired when possible, while executable or externally loaded content remains blocked.
Automatic recovery
The browser repairs missing closing HTML tags and tolerates a missing final CSS semicolon or brace. Unreadable declarations are discarded individually.
Executable code stays outside
Scripts, event handlers, iframes, embedded objects, interactive form controls, external @import rules and URL-based CSS are not kept in the document.
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.
Keep data collection in JavaScript, presentation in HTML/CSS, scheduled email on the host backend and the final decision with the user.