Appearance
React Adapter Guide (@continuejs/react) ​
The @continuejs/react package provides the useDraft hook for React 18 & 19 applications.
Controlled Input Form Example ​
tsx
import React, { useState, useEffect } from 'react';
import { useDraft } from '@continuejs/react';
import '@continuejs/ui';
export function ContactForm() {
const { hasDraft, restore, draft, lastSaved, clearDraft } = useDraft('contact-form', {
retention: '7d',
});
const [formData, setFormData] = useState({
name: '',
email: '',
message: '',
});
// Sync state to draft
useEffect(() => {
draft.setMultiple(formData);
draft.save();
}, [formData, draft]);
const handleRestore = async () => {
const saved = await restore();
if (saved) {
setFormData({
name: saved.name || '',
email: saved.email || '',
message: saved.message || '',
});
}
};
return (
<div className="form-container">
{hasDraft && (
<continuejs-banner
last-saved={lastSaved ? String(lastSaved) : ''}
ref={(el) => {
el?.addEventListener('continuejs-restore', handleRestore);
el?.addEventListener('continuejs-discard', clearDraft);
}}
/>
)}
<form onSubmit={(e) => { e.preventDefault(); clearDraft(); }}>
<input
type="text"
value={formData.name}
onChange={(e) => setFormData({ ...formData, name: e.target.value })}
/>
<input
type="email"
value={formData.email}
onChange={(e) => setFormData({ ...formData, email: e.target.value })}
/>
<textarea
value={formData.message}
onChange={(e) => setFormData({ ...formData, message: e.target.value })}
/>
<button type="submit">Submit</button>
</form>
</div>
);
}