Skip to content

Editing & drafts ​

Edit forms differ from create forms: the data already exists, only changes should be sent, and losing edits is painful.

Loading data ​

Initial values often arrive from the server after the form is created. Pass them to reset — they become the new baseline for dirty and changes:

ts
const form = useForm(UpdateUser, { initial: { name: '', email: '', bio: '' } });

onMounted(async () => {
  const user = await api.get(`/users/${id}`);
  form.reset({ name: user.name, email: user.email, bio: user.bio ?? '' });
});

Only changed fields — PATCH ​

form.changes contains only what the user changed. Together with a partial schema this is a ready PATCH:

ts
const submit = form.handleSubmit(async () => {
  await api.patch(`/users/${id}`, form.changes); // { bio: 'New bio' }
});
vue
<button :disabled="!form.dirty || form.submitting">Save</button>
<span v-if="form.isDirty('email')">Email will be changed</span>

After a successful submit the current values count as saved: dirty becomes false, changes becomes empty. If the handler calls setErrors (the server rejected the data), the changes stay unsaved.

Draft and leave warning ​

useDraft saves the input and restores it after a reload; useLeaveGuard warns when a tab with unsaved changes is closed:

ts
const form = useForm(Post, { initial: { title: '', body: '' } });
useDraft(form, `post-${id}`);
useLeaveGuard(form);

See also ​