Migration Guide
Guides for migrating to Form Guardian from other solutions or upgrading between versions.
📦 Migrating From
From localStorage
If you're currently using localStorage for form drafts, here's how to migrate:
Before (localStorage)
function MyForm() {
const [values, setValues] = useState({});
useEffect(() => {
// Load from localStorage
const saved = localStorage.getItem('my-form');
if (saved) {
setValues(JSON.parse(saved));
}
}, []);
useEffect(() => {
// Save to localStorage
localStorage.setItem('my-form', JSON.stringify(values));
}, [values]);
return <form>{/* ... */}</form>;
}
After (Form Guardian)
import { useFormAutosave } from '@form-guardian/react';
function MyForm() {
const { formRef } = useFormAutosave('my-form', {
autoRestore: true,
});
return <form ref={formRef}>{/* ... */}</form>;
}
Benefits
- ✅ Better Storage: IndexedDB has more space than localStorage (50MB+ vs 5-10MB)
- ✅ Automatic: No manual value tracking needed
- ✅ TTL Support: Automatic draft expiration
- ✅ Better Performance: Non-blocking storage operations
- ✅ Type Safety: TypeScript support
Migration Script
To migrate existing localStorage drafts:
import { saveDraftCore } from '@form-guardian/core';
async function migrateDraftsFromLocalStorage() {
// List of form IDs to migrate
const formIds = ['contact-form', 'registration-form', 'survey-form'];
for (const formId of formIds) {
const key = `draft-${formId}`; // Your localStorage key
const data = localStorage.getItem(key);
if (data) {
try {
const values = JSON.parse(data);
await saveDraftCore(formId, values);
console.log(`✅ Migrated ${formId}`);
// Optional: remove from localStorage
localStorage.removeItem(key);
} catch (error) {
console.error(`❌ Failed to migrate ${formId}:`, error);
}
}
}
}
// Run once on app initialization
migrateDraftsFromLocalStorage();
From Custom Solution
Before (Custom Implementation)
function useFormDraft(formId) {
const [data, setData] = useState(null);
useEffect(() => {
// Load draft
fetch(`/api/drafts/${formId}`)
.then(res => res.json())
.then(setData);
}, [formId]);
const saveDraft = useCallback((values) => {
fetch(`/api/drafts/${formId}`, {
method: 'POST',
body: JSON.stringify(values),
});
}, [formId]);
return { data, saveDraft };
}
After (Form Guardian)
import { useFormAutosave } from '@form-guardian/react';
function MyForm() {
const { formRef, clearDraft } = useFormAutosave('my-form', {
autoRestore: true,
onAfterSave: async (values) => {
// Optional: sync to backend
await fetch(`/api/drafts/${formId}`, {
method: 'POST',
body: JSON.stringify(values),
});
},
});
return <form ref={formRef}>{/* ... */}</form>;
}
Key Changes
- No manual state management - Form Guardian handles it
- Built-in debouncing - No need to implement yourself
- Automatic field detection - No need to track each input
- Local-first - Fast IndexedDB storage with optional backend sync
From react-autosave
Before (react-autosave)
import { useAutosave } from 'react-autosave';
function MyForm() {
const [values, setValues] = useState({});
useAutosave({
data: values,
onSave: (data) => {
localStorage.setItem('my-form', JSON.stringify(data));
},
});
return (
<form>
<input
value={values.name}
onChange={(e) => setValues({ ...values, name: e.target.value })}
/>
</form>
);
}
After (Form Guardian)
import { useFormAutosave } from '@form-guardian/react';
function MyForm() {
const { formRef } = useFormAutosave('my-form', {
autoRestore: true,
});
return (
<form ref={formRef}>
<input name="name" />
</form>
);
}
Advantages
- ✅ No manual state - Works with uncontrolled forms
- ✅ IndexedDB - Better storage than localStorage
- ✅ Framework agnostic - Works with any framework
- ✅ More features - TTL, analytics events, batching
Version Upgrades
Upgrading from 0.x to 1.x
Breaking Changes
-
Package names changed
# Before
npm install form-guardian
# After
npm install @form-guardian/react
# or
npm install @form-guardian/dom -
Import paths
// Before
import { useFormAutosave } from 'form-guardian';
// After
import { useFormAutosave } from '@form-guardian/react'; -
Options renamed
// Before
useFormAutosave('my-form', {
delay: 500,
restore: true,
});
// After
useFormAutosave('my-form', {
debounceMs: 500,
autoRestore: true,
});
Migration Steps
-
Update package.json
{
"dependencies": {
"@form-guardian/react": "^1.0.0"
}
} -
Update imports
// Replace all occurrences
import { useFormAutosave } from 'form-guardian';
// with
import { useFormAutosave } from '@form-guardian/react'; -
Update option names
delay→debounceMsrestore→autoRestoreprefix→storagePrefix
-
Test thoroughly
- Verify drafts are still saved
- Check restoration works
- Test with all your forms
Upgrading from 1.x to 2.x
(Future versions - check changelog when released)
🔄 Data Migration
Export Drafts
import { loadDraftCore } from '@form-guardian/core';
async function exportDrafts(formIds) {
const exports = {};
for (const formId of formIds) {
const draft = await loadDraftCore(formId);
if (draft) {
exports[formId] = draft;
}
}
// Save to file
const json = JSON.stringify(exports, null, 2);
const blob = new Blob([json], { type: 'application/json' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'form-drafts-export.json';
a.click();
}
Import Drafts
import { saveDraftCore } from '@form-guardian/core';
async function importDrafts(file) {
const text = await file.text();
const drafts = JSON.parse(text);
for (const [formId, draft] of Object.entries(drafts)) {
await saveDraftCore(formId, draft.values, {
ttl: draft.ttl,
});
}
console.log('✅ Import complete');
}
📚 Additional Resources
💬 Need Help?
If you encounter issues during migration:
- Check Troubleshooting guide
- Open a GitHub issue