Skip to main content

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

  1. No manual state management - Form Guardian handles it
  2. Built-in debouncing - No need to implement yourself
  3. Automatic field detection - No need to track each input
  4. 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

  1. Package names changed

    # Before
    npm install form-guardian

    # After
    npm install @form-guardian/react
    # or
    npm install @form-guardian/dom
  2. Import paths

    // Before
    import { useFormAutosave } from 'form-guardian';

    // After
    import { useFormAutosave } from '@form-guardian/react';
  3. Options renamed

    // Before
    useFormAutosave('my-form', {
    delay: 500,
    restore: true,
    });

    // After
    useFormAutosave('my-form', {
    debounceMs: 500,
    autoRestore: true,
    });

Migration Steps

  1. Update package.json

    {
    "dependencies": {
    "@form-guardian/react": "^1.0.0"
    }
    }
  2. Update imports

    // Replace all occurrences
    import { useFormAutosave } from 'form-guardian';
    // with
    import { useFormAutosave } from '@form-guardian/react';
  3. Update option names

    • delaydebounceMs
    • restoreautoRestore
    • prefixstoragePrefix
  4. 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:

  1. Check Troubleshooting guide
  2. Open a GitHub issue