Skip to content

$ cd ~/open-source

Open Source

PreviewForm 2.0: Review Form Data Before Submit

PreviewForm 2.0 adds an accessible review step before form submission. Install it from npm and use it with JavaScript or the jQuery adapter.

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 UI from 2013

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:

  1. Replace the old files with the npm package or versioned CDN assets.
  2. Upgrade jQuery to a supported version if you still need the adapter.
  3. Keep $(form).previewForm(...) and map old labels through yes, no, and extratext.
  4. Review password behavior. Modern PreviewForm masks sensitive values by default; show_password: true reveals only password controls through the legacy adapter.
  5. Test native validation, multiple submit buttons, checkbox groups, and server-side handling.
  6. 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.

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.

RK

Written by Rohit Kumar

10+ yrs modernizing high-risk PHP platforms and building reliable backend systems for enterprise teams.