I was inspired by this question from @hans about temporarily saving form data to allow users to continue editing it later on.
It’s also useful for when users lose their form input from refreshing or closing the page.
This guide will cover:
- Automatically saving form values in the browser
- Only store the fields we want
- Wait until users stop typing before saving
- Expire the saved data after 24 hours
- Clear saved data when the form is submitted
Notes
This demo uses the new Wix Forms
This topic should serve as a reference. Please conduct your own research before using it in a production environment.
Setup
Step 1: Give your form an ID
Open either the Wix Studio, or Wix Editor, and:
- Enable code
- Select your form
- Give it an ID - for example
myForm
Step 2: Add this code to your page
Paste the following code into the page’s code panel.
import { local } from "@wix/site-storage";
// Used to version the stored data
const FORM_VERSION = "v1";
// Fields you do NOT want to save (e.g. Personal Information)
const FIELDS_TO_EXCLUDE = ["firstName", "email"];
// Expire stored form data after 24 hours
const TTL = 1000 * 60 * 60 * 24;
function debounce(fn, delay) {
let timer;
return function (...args) {
clearTimeout(timer);
timer = setTimeout(() => fn.apply(this, args), delay);
};
}
function excludeFields(data) {
return Object.fromEntries(
Object.entries(data).filter(([key]) => !FIELDS_TO_EXCLUDE.includes(key))
);
}
$w.onReady(async function () {
// Step 1: Try to load saved data
const data = await local.getItem("formSubmission");
let parsed;
try {
parsed = JSON.parse(data);
} catch (e) {
parsed = null;
}
// Step 2: If saved data exists AND is valid AND not expired → restore it
if (
parsed &&
parsed.version === FORM_VERSION &&
parsed.timestamp &&
parsed.timestamp > Date.now() - TTL
) {
$w("#myForm").setFieldValues(parsed.values);
}
// Step 3: Save form values — but wait until the user stops typing
const saveForm = debounce(async (newValues) => {
const filtered = excludeFields(newValues);
await local.setItem("formSubmission", JSON.stringify({
version: FORM_VERSION,
timestamp: Date.now(),
values: filtered
}));
}, 500);
$w("#myForm").onFieldValueChange(saveForm);
// Step 4: Once form is submitted, remove saved data
$w("#myForm").onSubmit(() => {
local.removeItem("formSubmission");
});
});
What Each Part Does
local.getItem
/ setItem
/ removeItem
We use the @wix/site-storage
module to store the form values locally in the user’s browser - so they persist even if they refresh the page.
FORM_VERSION
If you ever change your form structure, older saved data might become incompatible.
Adding a FORM_VERSION
helps prevent issues:
parsed.version === FORM_VERSION
If the version doesn’t match, we ignore the saved data.
FIELDS_TO_EXCLUDE
Sometimes your form includes information you don’t want saved in the browser. For example:
- Names
- Email addresses
You probably don’t want to save or restore those.
So we filter them out:
function excludeFields(data) {
return Object.fromEntries(
Object.entries(data).filter(([key]) => !FIELDS_TO_EXCLUDE.includes(key))
);
}
TTL
(Time To Live)
We don’t want form data lingering forever.
This line ensures the data is only restored if it’s less than 24 hours old:
parsed.timestamp > Date.now() - TTL
If it’s expired, it’s ignored.
debounce
Forms can trigger onFieldValueChange
every time you type - which would hammer storage and slow things down.
So we debounce the save:
const saveForm = debounce(async (newValues) => { ... }, 500);
This means it waits until the user stops typing for 500ms before saving.
onSubmit
Once the user submits the form, we don’t want to keep their old data around. So we clear it:
$w("#myForm").onSubmit(() => {
local.removeItem("formSubmission");
});
Done!
That’s it - your form now:
- Auto-saves values to the browser
- Skips fields you don’t want
- Only restores if recent
- Clears after submit
- And won’t flood storage with every keystroke
Happy building