Variant memory
Switching away from a discriminated-union variant doesn't have to mean losing what was typed. Memory snapshots ride alongside the active state and rehydrate on switch-back. Opt out when the variants are unrelated or memory matters.
- Category
- Form option
- Option
useForm({ rememberVariants })- Default
true- Lifetime
- in-memory only (no persistence)
Two side-by-side forms with the same payment schema. Type into the card variant, switch to bank, switch back. The left form (rememberVariants: true) restores your card details; the right form (rememberVariants: false) starts fresh every switch. Same schema, opposite memory policy.
rememberVariants: true(default)
Switch back and the previous variant's typing comes home. Memory snapshots ride alongside the active state.
rememberVariants: false(every switch starts fresh)
No memory: every variant switch initialises from the schema's slim default. Type into card, switch to bank, switch back: card's typing is gone.
The default
useForm({
schema,
// rememberVariants: true is Attaform's default
})
Switching back to a previously-visited variant lands on its prior subtree, including nested fields. Each discriminated union at every nesting depth is independently memorized: a top-level union and a nested one each keep their own memory map.
Opting out
useForm({ schema, rememberVariants: false })
With false, every switch drops the outgoing variant's typed state. The new variant initializes from its slim default; the old data is gone.
Use the opt-out when:
- The variants represent unrelated data. A "contact preference" picker between phone and email should clear the phone when switching to email.
- Memory leaks user input you don't want re-applied. A wizard step that should reset when the user backtracks.
- Memory-constrained targets. Snapshots are small per-union, but a deeply nested form with many unions accumulates.
Per-app default
Set the default app-wide via the plugin:
createAttaform({
defaults: { rememberVariants: false },
})
Per-form useForm({ rememberVariants: true }) overrides back to memory-on for forms that want it.
What gets memorized
When the discriminator value flips:
- The current variant's subtree is snapshotted into the memory map keyed by the outgoing variant's discriminator value.
- The new variant's slim default seeds storage.
- On a subsequent switch to a remembered variant, the snapshot rehydrates over the seeded default.
What's stored: the value subtree, plus the blank marks under it. A field the user deliberately emptied comes back empty rather than showing its slim value, which keeps "the user cleared this" distinguishable from "nothing was ever entered" across a switch. Turn rememberVariants off and the blank marks go with the values.
Interaction state (touched, blurred, focused) is NOT part of the snapshot. It lives outside the union's storage tree, so it survives a switch either way, memory on or off.
Memory is in-memory only
Variant memory lives for the lifetime of the form instance and goes nowhere else. Nothing writes it to storage, to the URL, or to the server, so it does not survive a page reload, and a form rehydrated from a saved draft starts with an empty memory map: the first discriminator switch after the reload has no prior variant to restore.
For cross-session continuity of inactive-variant typing, carry it beyond the union boundary yourself. Watch the discriminator, mirror the outgoing subtree into a slot you save, and write it back when the user returns to that variant.
reset() and resetField() interactions
reset()clears all variant memory. The reset state becomes the new "no memory" baseline.resetField(path)clears any memory entry whose union path equals or sits underpath. Sibling unions keep theirs, and so does a union sitting above the reset path:resetField('notify.address')leaves the memory for the union atnotifyintact, because that snapshot self-corrects on the next switch-out.
Where to next
- Discriminated unions: the schema feature variant memory rides on top of.
reset&resetField: both interact with the memory map deterministically.- App-wide defaults: set
rememberVariantsonce for every form in the app.