In 2013, I was working on a Cake project when a client asked for one extra step: let users preview their form data before it reached the server. The idea was simple, but I knew developers kept solving the same problem with PHP, JavaScript, or jQuery on every project.
That request became previewForm, a small jQuery plugin that collected form values and asked the user to confirm them before submission. The original BufferNow article explained the basic setup, including the old show_password, extratext, yes, no, and title options.

The original PreviewForm registration screen from the 2013 plugin.
After years as a jQuery-era snapshot, I returned to it in July 2026 and rebuilt PreviewForm as a modern form-review library. The current npm package is PreviewForm 2.0.1. There is no hosted public demo yet; the source and local example remain in the repository.
From a jQuery Plugin to PreviewForm 2.0
The original Git history starts in June 2013. Version 1.x required jQuery, used separate JavaScript and CSS files, and expected labels to match form-field IDs. It solved the immediate problem: preview text fields, select boxes, radio buttons, checkboxes, and optionally passwords before submit.
The 2026 update is a clean rewrite rather than a renamed copy of the old plugin. PreviewForm 2.0 adds:
- A dependency-free TypeScript core
- Accessible dialog and page-takeover review modes
- Native form validation and submission behavior
- Labels from
<label>,<legend>, ARIA attributes, or custom resolvers - Text inputs, textareas, selects, radio groups, checkbox groups, outputs, hidden opt-in fields, and file metadata
- Masking or omission of password and sensitive-looking fields
- Edit actions, sections, lifecycle callbacks, and controller methods
- ESM, CommonJS, CDN-global, and TypeScript entry points
- An optional adapter for jQuery 3.7+ and 4.x
Version 2.0.1 includes the active submit button in ReviewContext.formData, groups same-name checkboxes into one entry, clarifies page-takeover mode, and hardens npm publishing.
Install PreviewForm from npm
For a new JavaScript or TypeScript application, install the core package:
npm install preview-form
The core has no runtime dependency and ships ESM, CommonJS, browser-global, CSS, and TypeScript entry points.
A valid native form is enough to start:
<form id="application-form">
<label for="full-name">Full name</label>
<input id="full-name" name="full_name" required>
<label for="email">Email</label>
<input id="email" name="email" type="email" required>
<label for="notes">Notes</label>
<textarea id="notes" name="notes"></textarea>
<button type="submit" name="action" value="send">Review and send</button>
</form>
Import attachReview and the packaged stylesheet:
import { attachReview } from "preview-form";
import "preview-form/styles.css";
const form = document.querySelector("#application-form");
const review = attachReview(form, {
title: "Review your answers",
description: "Check your information before sending.",
confirmLabel: "Send application",
cancelLabel: "Keep editing",
sensitiveFields: "mask",
files: "metadata"
});
PreviewForm listens for the form’s submit event. It runs native validation first, opens the review UI only when the form is valid, and uses the original submitter when the user confirms. Your existing form action and server-side processing remain responsible for the actual submission.
The returned controller supports:
review.open();
review.close();
review.refresh();
review.getContext();
review.destroy();
Use refresh() after values change and destroy() when the form is removed.
Use the CDN Build
If your page does not use a bundler, load the versioned CSS and browser build from a CDN:
<link rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/preview-form@2.0.1/dist/styles.css">
<script src="https://cdn.jsdelivr.net/npm/preview-form@2.0.1/dist/index.iife.js"></script>
<script>
PreviewForm.attachReview(
document.querySelector("#application-form"),
{
title: "Review your answers",
confirmLabel: "Send application"
}
);
</script>
There is no public hosted demo URL yet. Clone the repository and build its local example to test the controls.
Keep the jQuery API
PreviewForm 2.0 includes an optional compatibility adapter, so an existing jQuery application can move forward without rewriting every initialization call immediately.
Install both packages:
npm install preview-form jquery
Then install the adapter against your jQuery instance:
import $ from "jquery";
import { installJQueryAdapter } from "preview-form/jquery";
import "preview-form/styles.css";
installJQueryAdapter($);
$("#application-form").previewForm({
title: "Please review",
yes: "Send",
no: "Keep editing",
extratext: "Check your information before sending."
});
The adapter maps the old option names to the modern API:
| Old jQuery option | PreviewForm 2.0 option |
|---|---|
yes |
confirmLabel |
no |
cancelLabel |
extratext |
description |
title |
title |
show_password |
Legacy password-control reveal behavior |
It also supports lifecycle methods:
$("#application-form").previewForm("open");
$("#application-form").previewForm("refresh");
$("#application-form").previewForm("destroy");
For a non-module jQuery page, load jQuery first and then the adapter:
<link rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/preview-form@2.0.1/dist/styles.css">
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/preview-form@2.0.1/dist/jquery.iife.js"></script>
<script>
$("#application-form").previewForm({
title: "Please review",
yes: "Send",
no: "Keep editing"
});
</script>
The adapter uses the page’s existing jQuery instance. Supported versions are >=3.7.0 <5.0.0.
Configure the Review Step
These are the current core options in PreviewForm 2.0.1:
| Option | Default | Purpose |
|---|---|---|
mode |
"dialog" |
Use an accessible dialog or the current "page" takeover flow |
title |
"Review your answers" |
Heading shown above the collected values |
description |
"Check your information before sending." |
Supporting text below the heading |
confirmLabel |
"Send" |
Confirm button label |
cancelLabel |
"Keep editing" |
Cancel button label |
editLabel |
"Change" |
Per-field edit button label |
editable |
true |
Show or hide field-level edit actions |
includeEmpty |
true |
Include empty optional fields as Not provided |
sections |
true |
Group entries using fieldsets or custom section attributes |
sensitiveFields |
"mask" |
"mask", "omit", or "reveal" sensitive values |
files |
"metadata" |
"metadata", "filename", or "omit" file information |
labelResolver |
— | Return a custom display label for a control |
valueFormatter |
— | Format an entry’s displayed value |
onOpen |
— | Run after the review opens |
onCancel |
— | Run when the user returns to the form |
onConfirm |
— | Run before native submission; return false to stop it |
Add field-level behavior without writing a custom collector:
<input name="api_token" data-preview-mask="••••••••">
<input name="internal_note" data-preview-ignore>
<input name="reference" data-preview-label="Application reference">
<input type="hidden" name="source" value="newsletter"
data-preview-include="true">
<fieldset data-preview-section="Contact details">
</fieldset>
PreviewForm uses text rendering for displayed values rather than inserting user input as HTML. Password fields and sensitive-looking names such as tokens, card data, and security codes are masked by default.
Lifecycle callbacks receive a ReviewContext containing the form, active submitter, collected entries, and FormData:
attachReview(form, {
onConfirm(context) {
if (!context.formData.get("terms")) {
return false;
}
}
});
The active submit button’s name and value are included in formData in version 2.0.1.
Migrating from PreviewForm 1.x
Do not copy the old previewForm/previewForm.js and previewForm.css paths into a new project. Those files belong to the historical 1.x implementation and were removed when 2.0 was prepared.
For a gradual migration:
- Replace the old files with the npm package or versioned CDN assets.
- Upgrade jQuery to a supported version if you still need the adapter.
- Keep
$(form).previewForm(...)and map old labels throughyes,no, andextratext. - Review password behavior. Modern PreviewForm masks sensitive values by default;
show_password: truereveals only password controls through the legacy adapter. - Test native validation, multiple submit buttons, checkbox groups, and server-side handling.
- Move to
attachReview()when you are ready to remove the jQuery dependency.
Connected labels remain good HTML, while 2.0 also resolves legends, ARIA labels, custom labels, grouped controls, and name fallbacks.
Security, Limits, and Project Links
PreviewForm is a client-side review step, not a security boundary. The sensitiveFields option controls what the review interface displays, but callbacks, FormData, and other scripts can still inspect the original form. Continue validating, authorizing, and sanitizing every submission on the server.
For file controls, PreviewForm shows only the information allowed by the files policy. It does not preview or upload file contents. The current mode: "page" behavior hides the original form while an overlay-style review is visible; it is not yet a true inline page renderer.
The project is MIT licensed. The 2.0.1 package is published with npm provenance, and the repository’s release flow checks types, unit tests, the build, browser tests, and the package contents before publishing.
Contributor commands:
git clone https://github.com/aniketan/previewForm.git
cd previewForm
npm install
npm run typecheck
npm test
npm run build
npm run test:e2e
Project links:
What started as a one-project jQuery utility in 2013 is now a tested, typed package that can fit modern JavaScript applications while still giving old jQuery integrations a migration path.