A TypeScript library for React Hook Form persist functionality
npm install react-hook-form-storage
!npm package minimized gzipped size
!Tests


A TypeScript library that provides persistent storage functionality for React Hook Form, allowing you to automatically save and restore form data using localStorage, sessionStorage, or custom storage implementations.
- Installation
- Quick Start
- API Reference
- Configuration Options
- Advanced Usage
- Examples
- TypeScript Support
- Contributing
- License
``bash`
npm install react-hook-form-storage
`bash`
yarn add react-hook-form-storage
`bash`
pnpm add react-hook-form-storage
This library requires the following peer dependencies:
- react >= 16.8.0react-hook-form >= 7.0.0
-
Here's a basic example of how to use the library:
`typescript
import { useForm } from 'react-hook-form';
import { useFormStorage } from 'react-hook-form-storage';
interface FormData {
username: string;
email: string;
age: number;
}
function MyForm() {
const form = useForm
defaultValues: {
username: '',
email: '',
age: 0,
},
});
const { isRestored, isLoading } = useFormStorage('my-form', form, {
// Options go here
});
const onSubmit = (data: FormData) => {
console.log(data);
};
if (isLoading) {
return
return (
API Reference
useFormStorageThe main hook that provides storage functionality for your React Hook Form.
#### Parameters
-
key (string): A unique identifier for storing the form data in storage
- form (UseFormReturn): The form instance returned by useForm()
- options (UseFormStorageOptions): Configuration options (optional)#### Returns
`typescript
{
isRestored: boolean; // Indicates if data was restored from storage
isLoading: boolean; // Indicates if restoration is in progress
save: () => void; // Manual save function
}
`Configuration Options
$3
`typescript
interface UseFormStorageOptions {
storage?: Storage; // Storage implementation (default: localStorage)
included?: Array>; // Fields to include in storage
excluded?: Array>; // Fields to exclude from storage
onRestore?: (data: Partial) => void; // Callback when data is restored
onSave?: (data: Partial) => void; // Callback when data is saved
debounce?: number; // Debounce delay in milliseconds
dirty?: boolean; // Mark fields as dirty when restored
touched?: boolean; // Mark fields as touched when restored
validate?: boolean; // Validate fields when restored
serializer?: Record, Serializer>>; // Custom serializers
autoSave?: boolean; // Enable/disable automatic saving
autoRestore?: boolean; // Enable/disable automatic restoration
}
`$3
####
storage- Type:
Storage
- Default: localStorage
- Description: The storage implementation to use. Can be localStorage, sessionStorage, or a custom storage object that implements the Storage interface.`typescript
// Use sessionStorage instead of localStorage
useFormStorage('my-form', form, {
storage: sessionStorage,
});// Custom storage implementation
const customStorage = {
getItem: (key: string) => {
// Custom get logic
return myCustomStore.get(key);
},
setItem: (key: string, value: string) => {
// Custom set logic
myCustomStore.set(key, value);
},
removeItem: (key: string) => {
// Custom remove logic
myCustomStore.delete(key);
},
};
useFormStorage('my-form', form, {
storage: customStorage,
});
`####
included / excluded- Type:
Array
- Description: Control which fields are stored. Use included to specify only certain fields, or excluded to omit specific fields.`typescript
// Only store username and email
useFormStorage('my-form', form, {
included: ['username', 'email'],
});// Store all fields except password
useFormStorage('my-form', form, {
excluded: ['password'],
});
`####
onRestore / onSave- Type:
(data: Partial
- Description: Callbacks that are triggered when data is restored from storage or saved to storage.`typescript
useFormStorage('my-form', form, {
onRestore: (data) => {
console.log('Data restored:', data);
// Custom logic after restoration
},
onSave: (data) => {
console.log('Data saved:', data);
// Custom logic after saving
},
});
`####
debounce- Type:
number
- Default: undefined (no debouncing)
- Description: Debounce delay in milliseconds for auto-saving. Useful to prevent excessive storage writes.`typescript
// Save data 500ms after the user stops typing
useFormStorage('my-form', form, {
debounce: 500,
});
`####
dirty / touched / validate- Type:
boolean
- Default: false
- Description: Control form state when restoring data from storage.`typescript
useFormStorage('my-form', form, {
dirty: true, // Mark restored fields as dirty
touched: true, // Mark restored fields as touched
validate: true, // Validate restored fields
});
`####
serializer- Type:
Record
- Description: Custom serialization/deserialization for specific fields.`typescript
interface Serializer> {
serialize: (value: PathValue) => any;
deserialize: (value: any) => PathValue;
}// Example: Custom date serialization
useFormStorage('my-form', form, {
serializer: {
birthDate: {
serialize: (date: Date) => date.toISOString(),
deserialize: (dateString: string) => new Date(dateString),
},
},
});
`####
autoSave- Type:
boolean
- Default: true
- Description: Enable or disable automatic saving. When disabled, use the returned save function for manual control.`typescript
const { save } = useFormStorage('my-form', form, {
autoSave: false,
});// Manually save when needed
const handleSave = () => {
save();
};
`####
autoRestore- Type:
boolean
- Default: true
- Description: Enable or disable automatic restoration of form data from storage. When disabled, you can manually restore data using the restore function returned by the hook.`typescript
const { restore } = useFormStorage('my-form', form, {
autoRestore: false, // Disable automatic restoration
});// Manually restore data when needed
const handleRestore = () => {
restore();
};
`Advanced Usage
$3
`typescript
function ManualSaveForm() {
const form = useForm(); const { save, isRestored } = useFormStorage('manual-form', form, {
autoSave: false, // Disable auto-save
});
const handleManualSave = () => {
save(); // Manually trigger save
};
return (
);
}
`$3
`typescript
interface ComplexFormData {
user: {
name: string;
preferences: string[];
};
settings: Map;
createdAt: Date;
}function ComplexForm() {
const form = useForm();
useFormStorage('complex-form', form, {
serializer: {
'settings': {
serialize: (map: Map) => Object.fromEntries(map),
deserialize: (obj: Record) => new Map(Object.entries(obj)),
},
'createdAt': {
serialize: (date: Date) => date.toISOString(),
deserialize: (dateString: string) => new Date(dateString),
},
},
});
return (
// Form JSX
);
}
`$3
`typescript
function ConditionalStorageForm() {
const [enableStorage, setEnableStorage] = useState(true);
const form = useForm(); useFormStorage('conditional-form', form, {
autoSave: enableStorage,
onSave: (data) => {
if (enableStorage) {
console.log('Data saved:', data);
}
},
});
return (
);
}
`Examples
$3
`typescript
import { useForm } from 'react-hook-form';
import { useFormStorage } from 'react-hook-form-storage';interface ContactForm {
name: string;
email: string;
message: string;
}
export function ContactForm() {
const form = useForm({
defaultValues: {
name: '',
email: '',
message: '',
},
});
const { isRestored } = useFormStorage('contact-form', form);
return (
);
}
`$3
`typescript
interface CheckoutForm {
shippingAddress: {
street: string;
city: string;
zipCode: string;
};
billingAddress: {
street: string;
city: string;
zipCode: string;
};
paymentMethod: 'credit' | 'debit' | 'paypal';
cardNumber: string;
expiryDate: string;
}export function CheckoutForm() {
const form = useForm();
useFormStorage('checkout-form', form, {
excluded: ['cardNumber', 'expiryDate'], // Exclude sensitive payment info
debounce: 1000,
onSave: (data) => {
console.log('Checkout progress saved');
},
});
return (
);
}
`TypeScript Support
This library is written in TypeScript and provides full type safety:
`typescript
// Types are automatically inferred from your form schema
interface UserForm {
name: string;
age: number;
preferences: string[];
}const form = useForm();
// TypeScript will ensure field names are valid
useFormStorage('user-form', form, {
included: ['name', 'age'], // ✅ Valid field names
excluded: ['invalid'], // ❌ TypeScript error - 'invalid' doesn't exist
});
`Browser Compatibility
- Modern browsers with ES2017+ support
- localStorage/sessionStorage API support
- React 16.8+ (hooks support)
Performance Considerations
- Use
debounce option to limit storage writes
- Consider included/excluded options for large forms
- The library uses React's built-in optimization (useCallback, useMemo)
- Storage operations are performed asynchronously when possible`typescript
useFormStorage('my-form', form, {
onSave: (data) => {
// This callback only fires on successful saves
console.log('Data saved successfully');
},
onRestore: (data) => {
// This callback only fires on successful restoration
console.log('Data restored successfully');
},
});
``Contributions are welcome!
MIT License.
---
For more examples and advanced usage patterns, please visit our GitHub repository.