@form-guardian/dom
Universal DOM-based form autosave. Works with any framework or vanilla HTML forms.
Installation
npm install @form-guardian/dom
attachFormAutosave(options)
Main function to attach autosave functionality to a form.
Import:
import { attachFormAutosave } from '@form-guardian/dom';
Parameters:
formId(string, required) - Unique identifier for the formroot(HTMLFormElement | HTMLElement, required) - Root element (form or container)autoRestore(boolean, optional) - Auto-restore on mount (default: false)debounceMs(number, optional) - Debounce delay in milliseconds (default: 500)ttl(object | number, optional) - Time to live for draftsblacklist(string[], optional) - CSS selectors for fields to excludewhitelist(string[], optional) - CSS selectors for fields to includefieldSelector(string, optional) - Selector for fields to track (default: 'input, textarea, [contenteditable="true"]')excludeSelector(string, optional) - Selector for fields to exclude (default: 'input[type="submit"], input[type="button"], input[type="reset"]')getFieldKey(function, optional) - Function to get field keyonSave(function, optional) - Callback when draft is saved (legacy)onRestore(function, optional) - Callback when draft is restored (legacy)onBeforeSave(function, optional) - Callback before draft is savedonAfterSave(function, optional) - Callback after draft is successfully savedonBeforeRestore(function, optional) - Callback before draft is restoredonAfterRestore(function, optional) - Callback after draft is successfully restoredonDraftExpired(function, optional) - Callback when draft expires due to TTLbatchSaveInterval(number, optional) - Batch save interval in milliseconds (0 = disabled, default: disabled)includeOrigin(boolean, optional) - Include origin in draft ID (default: true)storagePrefix(string, optional) - Storage key prefix (default: 'fg')
Returns: FormAutosaveHandle
Example:
const handle = attachFormAutosave({
formId: 'my-form',
root: document.getElementById('my-form'),
autoRestore: true,
debounceMs: 300,
onBeforeSave: async (values) => {
console.log('Saving draft...', values);
},
onAfterSave: async (values) => {
console.log('Draft saved successfully!');
},
});
// Methods available on handle:
handle.restore(); // Restore draft
handle.clear(); // Clear draft
handle.destroy(); // Remove event listeners
handle.hasDraft(); // Check if draft exists
handle.getCurrentValues(); // Get current form values
FormAutosaveHandle
Object returned by attachFormAutosave().
Methods
restore(): Promise<void>
Restore draft values to the form.
await handle.restore();
clear(): Promise<void>
Clear draft from storage.
await handle.clear();
destroy(): void
Remove all event listeners and clean up. Call this when unmounting.
handle.destroy();
getCurrentValues(): Promise<T>
Get current form values as an object.
const values = await handle.getCurrentValues();
console.log(values); // { name: 'John', email: 'john@example.com' }
hasDraft(): Promise<boolean>
Check if a draft exists for this form.
const exists = await handle.hasDraft();
if (exists) {
console.log('Draft found!');
}
getDraftMeta(): Promise<DraftMeta | null>
Get draft metadata (timestamp, formId, etc.) without loading values.
const meta = await handle.getDraftMeta();
if (meta) {
console.log('Draft last updated:', new Date(meta.updatedAt));
}
Use Cases
Vanilla JavaScript
import { attachFormAutosave } from '@form-guardian/dom';
const form = document.getElementById('contact-form');
const autosave = attachFormAutosave({
formId: 'contact-form',
root: form,
autoRestore: true,
debounceMs: 500,
});
form.addEventListener('submit', async (e) => {
e.preventDefault();
// Clear draft after successful submission
await autosave.clear();
// Submit form data...
});
Vue 3
<script setup>
import { onMounted, onBeforeUnmount, ref } from 'vue';
import { attachFormAutosave } from '@form-guardian/dom';
const formRef = ref(null);
let autosave = null;
onMounted(() => {
autosave = attachFormAutosave({
formId: 'my-form',
root: formRef.value,
autoRestore: true,
});
});
onBeforeUnmount(() => {
if (autosave) {
autosave.destroy();
}
});
const handleSubmit = async () => {
await autosave.clear();
// Submit logic...
};
</script>
<template>
<form ref="formRef" @submit.prevent="handleSubmit">
<!-- form fields -->
</form>
</template>
Angular
import { Component, ElementRef, OnInit, OnDestroy, ViewChild } from '@angular/core';
import { attachFormAutosave, FormAutosaveHandle } from '@form-guardian/dom';
@Component({
selector: 'app-my-form',
template: `<form #myForm (submit)="onSubmit($event)">...</form>`
})
export class MyFormComponent implements OnInit, OnDestroy {
@ViewChild('myForm') formElement!: ElementRef;
private autosave: FormAutosaveHandle | null = null;
ngOnInit() {
this.autosave = attachFormAutosave({
formId: 'my-form',
root: this.formElement.nativeElement,
autoRestore: true,
});
}
ngOnDestroy() {
if (this.autosave) {
this.autosave.destroy();
}
}
async onSubmit(event: Event) {
event.preventDefault();
await this.autosave?.clear();
// Submit logic...
}
}