data-autosave
Automatically save form drafts to localStorage as the user types. Restores on page reload with a toast notification. Clears on submit or reset.
Overview
The data-autosave attribute automatically persists form data to localStorage as the user types. If the page is accidentally closed or refreshed, the draft is restored on the next visit with a toast notification. The draft is cleared when the form is submitted or reset.
<form data-autosave="contact-form"> <input name="name" placeholder="Name"> <textarea name="message" placeholder="Message"></textarea> <button type="submit">Send</button></form>
How It Works
Add data-autosave to any <form> element with a unique key as the value. The init script:
- Attaches delegated
inputandchangeevent listeners on the form - On every field change, debounces for 500ms then serializes all named fields to a JSON object
- Saves the object to
localStoragewith the keyvb-autosave:{key}and a timestamp - On page load, checks for a non-expired draft (24-hour expiry)
- If a draft exists, restores field values and fires
inputevents so other enhancements update - Shows a "Draft restored" toast notification via
toast-msgif available - Sets
data-autosave-initto prevent double-binding
Password fields (type="password") and file inputs (type="file") are always skipped — sensitive data and file references are never stored.
Attributes
| Attribute | Value | Description |
|---|---|---|
data-autosave |
string (required) | A unique storage key for this form. Used as part of the localStorage key: vb-autosave:{key}. |
data-autosave-init |
boolean | Set automatically to prevent double-binding. Do not set manually. |
Storage Format
The draft is stored as a JSON object in localStorage. Each named field in the form becomes a key-value pair. A _ts timestamp is included for expiry checking.
<thead> <tr> <th>Detail</th> <th>Value</th> </tr> </thead> <tbody> <tr> <td>Key format</td> <td><code>vb-autosave:{<em>key</em>}</code></td> </tr> <tr> <td>Debounce</td> <td>500ms after last input</td> </tr> <tr> <td>Expiry</td> <td>24 hours from last save</td> </tr> <tr> <td>Skipped types</td> <td><code>password</code>, <code>file</code></td> </tr> </tbody> </table> </section> <section> <h2>Multiple Forms</h2> <p>Each form on a page must have a unique <code>data-autosave</code> key. The key is used directly in the <code>localStorage</code> key, so collisions between forms on different pages are avoided by using descriptive names.</p> <code-block language="html" show-lines label="Multiple forms with unique keys" data-escape><!-- Each form needs a unique key --><form data-autosave="signup-form"> <input name="email" type="email" placeholder="Email"> <input name="username" placeholder="Username"> <button type="submit">Sign Up</button></form> <form data-autosave="feedback-form"> <textarea name="feedback" placeholder="Your feedback"></textarea> <button type="submit">Submit</button></form>
Checkboxes and Radios
Checkbox and radio inputs are handled correctly during both save and restore:
- Checkboxes — stored as
"on"when checked,""when unchecked. On restore, thecheckedproperty is set accordingly. - Radio buttons — only the checked radio's value is stored for the group name. On restore, the matching radio is checked.
<form data-autosave="preferences"> <fieldset> <legend>Notifications</legend> <label> <input type="checkbox" name="email-notify" value="yes"> Email notifications </label> <label> <input type="checkbox" name="sms-notify" value="yes"> SMS notifications </label> </fieldset> <fieldset> <legend>Theme</legend> <label> <input type="radio" name="theme" value="light"> Light </label> <label> <input type="radio" name="theme" value="dark"> Dark </label> </fieldset> <button type="submit">Save</button></form>
With Other Enhancements
When a draft is restored, input events are fired on each restored field. This ensures other Vanilla Breeze enhancements that listen for input events — such as data-count, data-grow, and data-show-when — update correctly.
<form data-autosave="registration" class="stacked"> <form-field> <label for="reg-email">Email</label> <input type="email" id="reg-email" name="email" required> </form-field> <form-field> <label for="reg-name">Full Name</label> <input type="text" id="reg-name" name="fullname" required> <small slot="help">As it appears on your ID.</small> </form-field> <form-field> <label for="reg-bio">Bio</label> <textarea id="reg-bio" name="bio" data-count="200" data-grow></textarea> </form-field> <button type="submit">Register</button></form>
Toast Notification
When a draft is restored, a toast notification is displayed if toast-msg is available on the page. The toast uses the following configuration:
- Message: "Draft restored"
- Variant:
info - Duration: 3000ms (auto-dismisses)
If toast-msg is not present, the draft is still restored silently without a notification.
Clear Behavior
The autosave draft is automatically cleared in two scenarios:
- Form submit — the draft is removed from
localStoragewhen the form is submitted - Form reset — the draft is removed when the form is reset via a reset button or
form.reset()
Styling
The autosave attribute itself has no visual output. The only visible indicator is the toast notification on restore, which inherits styles from toast-msg.
/* The toast notification uses toast-msg if available *//* Customize the restore notification via toast-msg styles */toast-msg::part(toast) { --toast-bg: var(--color-surface-raised); --toast-color: var(--color-text);}
All behavior is gated on data-autosave-init. Without JavaScript, the form works normally — data simply is not persisted to localStorage.
Accessibility
- The "Draft restored" toast notification is announced by screen readers via
toast-msg's accessible live region - Restored form state preserves the user's previous work, reducing frustration from accidental navigation
- No visual layout changes occur during restore — fields are populated in place
- Firing
inputevents on restore ensures dependent enhancements (character counts, conditional fields) are in the correct state for assistive technology - Password and file fields are excluded from storage for security — users are not given a false sense of persistence for sensitive data
- Without JavaScript, the form works as a standard HTML form — progressive enhancement