[{"data":1,"prerenderedAt":1214},["ShallowReactive",2],{"content-\u002Fdocs\u002Frecipes\u002Fpersistence-edge-cases":3},{"id":4,"title":5,"body":6,"description":16,"extension":1208,"meta":1209,"navigation":84,"path":1210,"seo":1211,"stem":1212,"__hash__":1213},"docs\u002Fdocs\u002Frecipes\u002Fpersistence-edge-cases.md","Persistence edge cases",{"type":7,"value":8,"toc":1185},"minimark",[9,13,17,26,33,144,147,178,185,233,238,242,245,269,272,276,283,287,298,310,324,328,335,342,346,355,360,378,479,519,526,536,664,705,716,728,735,760,971,983,991,994,1041,1058,1062,1071,1075,1078,1100,1103,1107,1153,1157,1181],[10,11,5],"h1",{"id":12},"persistence-edge-cases",[14,15,16],"p",{},"Imperative checkpoint and clear APIs, the four component-binding\npatterns, and the gotchas that come up under unusual storage\nconditions.",[18,19,21,22],"h2",{"id":20},"imperative-checkpoint-via-formpersist","Imperative checkpoint via ",[23,24,25],"code",{},"form.persist()",[14,27,28,29,32],{},"For \"Save Draft\" buttons, ",[23,30,31],{},"beforeunload"," handlers, or wizard\nsection boundaries:",[34,35,40],"pre",{"className":36,"code":37,"language":38,"meta":39,"style":39},"language-ts shiki shiki-themes github-light github-dark","const form = useForm({ schema, key: 'wizard', persist: { storage: 'local' } })\n\nasync function onSaveStep() {\n  await form.persist('step1')\n  await form.persist('step2')\n}\n","ts","",[23,41,42,79,86,101,122,138],{"__ignoreMap":39},[43,44,47,51,55,58,62,66,70,73,76],"span",{"class":45,"line":46},"line",1,[43,48,50],{"class":49},"szBVR","const",[43,52,54],{"class":53},"sj4cs"," form",[43,56,57],{"class":49}," =",[43,59,61],{"class":60},"sScJk"," useForm",[43,63,65],{"class":64},"sVt8B","({ schema, key: ",[43,67,69],{"class":68},"sZZnC","'wizard'",[43,71,72],{"class":64},", persist: { storage: ",[43,74,75],{"class":68},"'local'",[43,77,78],{"class":64}," } })\n",[43,80,82],{"class":45,"line":81},2,[43,83,85],{"emptyLinePlaceholder":84},true,"\n",[43,87,89,92,95,98],{"class":45,"line":88},3,[43,90,91],{"class":49},"async",[43,93,94],{"class":49}," function",[43,96,97],{"class":60}," onSaveStep",[43,99,100],{"class":64},"() {\n",[43,102,104,107,110,113,116,119],{"class":45,"line":103},4,[43,105,106],{"class":49},"  await",[43,108,109],{"class":64}," form.",[43,111,112],{"class":60},"persist",[43,114,115],{"class":64},"(",[43,117,118],{"class":68},"'step1'",[43,120,121],{"class":64},")\n",[43,123,125,127,129,131,133,136],{"class":45,"line":124},5,[43,126,106],{"class":49},[43,128,109],{"class":64},[43,130,112],{"class":60},[43,132,115],{"class":64},[43,134,135],{"class":68},"'step2'",[43,137,121],{"class":64},[43,139,141],{"class":45,"line":140},6,[43,142,143],{"class":64},"}\n",[14,145,146],{},"A one-shot read-merge-write:",[148,149,150,154,157,160,171],"ul",{},[151,152,153],"li",{},"Bypasses the per-element opt-in gate.",[151,155,156],{},"Bypasses the debouncer — flushes pending writes first.",[151,158,159],{},"Preserves untouched paths in storage.",[151,161,162,163,166,167,170],{},"Throws ",[23,164,165],{},"SensitivePersistFieldError"," on heuristic-matched paths\nunless ",[23,168,169],{},"{ acknowledgeSensitive: true }",".",[151,172,173,174,177],{},"Silent no-op when ",[23,175,176],{},"persist:"," isn't configured.",[18,179,181,182],{"id":180},"wiping-a-draft-via-formclearpersisteddraft","Wiping a draft via ",[23,183,184],{},"form.clearPersistedDraft()",[34,186,188],{"className":36,"code":187,"language":38,"meta":39,"style":39},"\u002F\u002F Wipe the entire draft.\nawait form.clearPersistedDraft()\n\n\u002F\u002F Wipe one path's slot.\nawait form.clearPersistedDraft('email')\n",[23,189,190,196,209,213,218],{"__ignoreMap":39},[43,191,192],{"class":45,"line":46},[43,193,195],{"class":194},"sJ8bj","\u002F\u002F Wipe the entire draft.\n",[43,197,198,201,203,206],{"class":45,"line":81},[43,199,200],{"class":49},"await",[43,202,109],{"class":64},[43,204,205],{"class":60},"clearPersistedDraft",[43,207,208],{"class":64},"()\n",[43,210,211],{"class":45,"line":88},[43,212,85],{"emptyLinePlaceholder":84},[43,214,215],{"class":45,"line":103},[43,216,217],{"class":194},"\u002F\u002F Wipe one path's slot.\n",[43,219,220,222,224,226,228,231],{"class":45,"line":124},[43,221,200],{"class":49},[43,223,109],{"class":64},[43,225,205],{"class":60},[43,227,115],{"class":64},[43,229,230],{"class":68},"'email'",[43,232,121],{"class":64},[14,234,235,237],{},[23,236,205],{}," does NOT touch in-memory form state, and does\nNOT disable any active opt-ins — future writes from opted-in\nbindings will re-populate the storage entry.",[18,239,241],{"id":240},"cross-sfc-behavior","Cross-SFC behavior",[14,243,244],{},"Two SFCs sharing a key share the same FormStore and the same\npersistence registry. Opt-ins are per-DOM-element, not per-SFC:",[148,246,247,257,266],{},[151,248,249,250,252,253,256],{},"SFC A renders an input bound to ",[23,251,230],{}," with ",[23,254,255],{},"persist: true"," →\nA's element opted in.",[151,258,259,260,262,263,265],{},"SFC B renders an input bound to ",[23,261,230],{}," without ",[23,264,112],{}," → B's\nelement NOT opted in.",[151,267,268],{},"Typing in A persists. Typing in B doesn't.",[14,270,271],{},"Unmount SFC A and B's typing stops persisting (no opt-ins remain).\nRe-mount A and the new element gets a fresh opt-in. No special\ncoordination logic — element-level identity does the right thing.",[18,273,275],{"id":274},"keeping-the-draft-after-submit","Keeping the draft after submit",[14,277,278,279,282],{},"Default: a successful submit clears the entry wholesale. Set\n",[23,280,281],{},"clearOnSubmitSuccess: false"," to keep it (useful for wizards with\nreview pages, or if submit might return a retryable server error).",[18,284,286],{"id":285},"cross-tab-semantics","Cross-tab semantics",[14,288,289,292,293,297],{},[23,290,291],{},"localStorage"," writes from two tabs race; the library does NOT\ncoordinate — ",[294,295,296],"strong",{},"last-write-wins",". Two cases:",[148,299,300,303],{},[151,301,302],{},"Tab A is mid-debounce; Tab B writes; Tab A's debounce overwrites.",[151,304,305,306,309],{},"The library doesn't subscribe to the ",[23,307,308],{},"storage"," event — fresh\nwrites from another tab don't replay into the live form.",[14,311,312,313,316,317,320,321,170],{},"If multi-tab consistency matters, use ",[23,314,315],{},"'session'"," (tab-scoped) or a\ncustom ",[23,318,319],{},"FormStorage"," adapter that coordinates via\n",[23,322,323],{},"BroadcastChannel",[18,325,327],{"id":326},"storage-degradation","Storage degradation",[14,329,330,331,334],{},"Backend failures (quota exceeded, Safari private mode, IndexedDB\nblocked) log a one-shot ",[23,332,333],{},"console.warn"," per form in dev mode and are\nsilently swallowed in production — no user-visible recovery path.",[14,336,337,338,341],{},"Check ",[23,339,340],{},"console"," in dev if persistence appears to drop writes.",[18,343,345],{"id":344},"component-support","Component support",[14,347,348,351,352,170],{},[23,349,350],{},"\u003CMyComponent v-register=\"register('name')\" \u002F>"," is supported through\nfour patterns, each appropriate for different component shapes. The\nrecommended pattern (for most cases) is ",[23,353,354],{},"useRegister()",[356,357,359],"h3",{"id":358},"_1-native-form-element-root","1. Native form-element root",[14,361,362,363,366,367,370,371,370,374,377],{},"When ",[23,364,365],{},"MyComponent","'s root is ",[23,368,369],{},"\u003Cinput>"," \u002F ",[23,372,373],{},"\u003Cselect>",[23,375,376],{},"\u003Ctextarea>",",\nthe directive lands on the rendered DOM root and persistence \u002F\nfocus \u002F blur tracking apply directly with no extra wiring.",[34,379,383],{"className":380,"code":381,"language":382,"meta":39,"style":39},"language-vue shiki shiki-themes github-light github-dark","\u003C!-- MyInput.vue -->\n\u003Cscript setup lang=\"ts\">\n  defineOptions({ inheritAttrs: false })\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003Cinput v-bind=\"$attrs\" \u002F>\n\u003C\u002Ftemplate>\n","vue",[23,384,385,390,414,428,437,441,450,470],{"__ignoreMap":39},[43,386,387],{"class":45,"line":46},[43,388,389],{"class":194},"\u003C!-- MyInput.vue -->\n",[43,391,392,395,399,402,405,408,411],{"class":45,"line":81},[43,393,394],{"class":64},"\u003C",[43,396,398],{"class":397},"s9eBZ","script",[43,400,401],{"class":60}," setup",[43,403,404],{"class":60}," lang",[43,406,407],{"class":64},"=",[43,409,410],{"class":68},"\"ts\"",[43,412,413],{"class":64},">\n",[43,415,416,419,422,425],{"class":45,"line":88},[43,417,418],{"class":60},"  defineOptions",[43,420,421],{"class":64},"({ inheritAttrs: ",[43,423,424],{"class":53},"false",[43,426,427],{"class":64}," })\n",[43,429,430,433,435],{"class":45,"line":103},[43,431,432],{"class":64},"\u003C\u002F",[43,434,398],{"class":397},[43,436,413],{"class":64},[43,438,439],{"class":45,"line":124},[43,440,85],{"emptyLinePlaceholder":84},[43,442,443,445,448],{"class":45,"line":140},[43,444,394],{"class":64},[43,446,447],{"class":397},"template",[43,449,413],{"class":64},[43,451,453,456,459,462,464,467],{"class":45,"line":452},7,[43,454,455],{"class":64},"  \u003C",[43,457,458],{"class":397},"input",[43,460,461],{"class":60}," v-bind",[43,463,407],{"class":64},[43,465,466],{"class":68},"\"$attrs\"",[43,468,469],{"class":64}," \u002F>\n",[43,471,473,475,477],{"class":45,"line":472},8,[43,474,432],{"class":64},[43,476,447],{"class":397},[43,478,413],{"class":64},[34,480,482],{"className":380,"code":481,"language":382,"meta":39,"style":39},"\u003C!-- consumer -->\n\u003CMyInput v-register=\"register('name')\" \u002F>\n",[23,483,484,489],{"__ignoreMap":39},[43,485,486],{"class":45,"line":46},[43,487,488],{"class":194},"\u003C!-- consumer -->\n",[43,490,491,493,496,499,501,504,507,509,512,515,517],{"class":45,"line":81},[43,492,394],{"class":64},[43,494,495],{"class":397},"MyInput",[43,497,498],{"class":60}," v-register",[43,500,407],{"class":64},[43,502,503],{"class":68},"\"",[43,505,506],{"class":60},"register",[43,508,115],{"class":64},[43,510,511],{"class":68},"'name'",[43,513,514],{"class":64},")",[43,516,503],{"class":68},[43,518,469],{"class":64},[356,520,522,523,525],{"id":521},"_2-non-form-root-useregister-recommended","2. Non-form root → ",[23,524,354],{}," (recommended)",[14,527,528,529,531,532,535],{},"When the component wraps a native input in styling, call\n",[23,530,354],{}," in the child's setup and re-bind ",[23,533,534],{},"v-register"," onto\nan inner native element:",[34,537,539],{"className":380,"code":538,"language":382,"meta":39,"style":39},"\u003C!-- StyledInput.vue -->\n\u003Cscript setup lang=\"ts\">\n  import { useRegister } from 'attaform'\n  const register = useRegister()\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003Cdiv class=\"wrapper\">\n    \u003Cinput v-register=\"register\" \u002F>\n  \u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n",[23,540,541,546,562,576,591,599,603,611,628,645,655],{"__ignoreMap":39},[43,542,543],{"class":45,"line":46},[43,544,545],{"class":194},"\u003C!-- StyledInput.vue -->\n",[43,547,548,550,552,554,556,558,560],{"class":45,"line":81},[43,549,394],{"class":64},[43,551,398],{"class":397},[43,553,401],{"class":60},[43,555,404],{"class":60},[43,557,407],{"class":64},[43,559,410],{"class":68},[43,561,413],{"class":64},[43,563,564,567,570,573],{"class":45,"line":88},[43,565,566],{"class":49},"  import",[43,568,569],{"class":64}," { useRegister } ",[43,571,572],{"class":49},"from",[43,574,575],{"class":68}," 'attaform'\n",[43,577,578,581,584,586,589],{"class":45,"line":103},[43,579,580],{"class":49},"  const",[43,582,583],{"class":53}," register",[43,585,57],{"class":49},[43,587,588],{"class":60}," useRegister",[43,590,208],{"class":64},[43,592,593,595,597],{"class":45,"line":124},[43,594,432],{"class":64},[43,596,398],{"class":397},[43,598,413],{"class":64},[43,600,601],{"class":45,"line":140},[43,602,85],{"emptyLinePlaceholder":84},[43,604,605,607,609],{"class":45,"line":452},[43,606,394],{"class":64},[43,608,447],{"class":397},[43,610,413],{"class":64},[43,612,613,615,618,621,623,626],{"class":45,"line":472},[43,614,455],{"class":64},[43,616,617],{"class":397},"div",[43,619,620],{"class":60}," class",[43,622,407],{"class":64},[43,624,625],{"class":68},"\"wrapper\"",[43,627,413],{"class":64},[43,629,631,634,636,638,640,643],{"class":45,"line":630},9,[43,632,633],{"class":64},"    \u003C",[43,635,458],{"class":397},[43,637,498],{"class":60},[43,639,407],{"class":64},[43,641,642],{"class":68},"\"register\"",[43,644,469],{"class":64},[43,646,648,651,653],{"class":45,"line":647},10,[43,649,650],{"class":64},"  \u003C\u002F",[43,652,617],{"class":397},[43,654,413],{"class":64},[43,656,658,660,662],{"class":45,"line":657},11,[43,659,432],{"class":64},[43,661,447],{"class":397},[43,663,413],{"class":64},[34,665,667],{"className":380,"code":666,"language":382,"meta":39,"style":39},"\u003C!-- consumer -->\n\u003CStyledInput v-register=\"register('email', { persist: true })\" \u002F>\n",[23,668,669,673],{"__ignoreMap":39},[43,670,671],{"class":45,"line":46},[43,672,488],{"class":194},[43,674,675,677,680,682,684,686,688,690,692,695,698,701,703],{"class":45,"line":81},[43,676,394],{"class":64},[43,678,679],{"class":397},"StyledInput",[43,681,498],{"class":60},[43,683,407],{"class":64},[43,685,503],{"class":68},[43,687,506],{"class":60},[43,689,115],{"class":64},[43,691,230],{"class":68},[43,693,694],{"class":64},", { persist: ",[43,696,697],{"class":53},"true",[43,699,700],{"class":64}," })",[43,702,503],{"class":68},[43,704,469],{"class":64},[14,706,707,708,711,712,715],{},"The parent directive detects the ",[23,709,710],{},"useRegister"," sentinel and skips\nlistener attachment on the component root; the inner\n",[23,713,714],{},"v-register=\"register\""," gets the full lifecycle — listeners,\nelement registration, focus\u002Fblur\u002Ftouched, persistence.",[14,717,718,720,721,724,725,727],{},[23,719,354],{}," returns ",[23,722,723],{},"ComputedRef\u003CRegisterValue | undefined>",". A\nstandalone child (no parent passing ",[23,726,534],{},") gets a no-op\nbinding plus a dev-warn, not a crash.",[356,729,731,732],{"id":730},"_3-compound-components-injectform","3. Compound components → ",[23,733,734],{},"injectForm",[14,736,737,738,741,742,745,746,745,749,752,753,755,756,759],{},"For components that touch multiple fields (e.g. an ",[23,739,740],{},"AddressBlock","\nwith its own ",[23,743,744],{},"street",", ",[23,747,748],{},"city",[23,750,751],{},"zip"," inputs), use the existing\n",[23,754,734],{}," API and call ",[23,757,758],{},"ctx.register('a.b.c')"," directly:",[34,761,763],{"className":380,"code":762,"language":382,"meta":39,"style":39},"\u003C!-- AddressBlock.vue -->\n\u003Cscript setup lang=\"ts\">\n  import { injectForm } from 'attaform'\n  type SignupForm = { address: { street: string; city: string; zip: string } }\n  const ctx = injectForm\u003CSignupForm>('signup')\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003Cdiv v-if=\"ctx\">\n    \u003Cinput v-register=\"ctx.register('address.street')\" \u002F>\n    \u003Cinput v-register=\"ctx.register('address.city')\" \u002F>\n    \u003Cinput v-register=\"ctx.register('address.zip')\" \u002F>\n  \u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n",[23,764,765,770,786,797,846,871,879,883,891,907,922,937,953,962],{"__ignoreMap":39},[43,766,767],{"class":45,"line":46},[43,768,769],{"class":194},"\u003C!-- AddressBlock.vue -->\n",[43,771,772,774,776,778,780,782,784],{"class":45,"line":81},[43,773,394],{"class":64},[43,775,398],{"class":397},[43,777,401],{"class":60},[43,779,404],{"class":60},[43,781,407],{"class":64},[43,783,410],{"class":68},[43,785,413],{"class":64},[43,787,788,790,793,795],{"class":45,"line":88},[43,789,566],{"class":49},[43,791,792],{"class":64}," { injectForm } ",[43,794,572],{"class":49},[43,796,575],{"class":68},[43,798,799,802,805,807,810,814,817,819,821,823,826,829,831,833,835,837,839,841,843],{"class":45,"line":103},[43,800,801],{"class":49},"  type",[43,803,804],{"class":60}," SignupForm",[43,806,57],{"class":49},[43,808,809],{"class":64}," { ",[43,811,813],{"class":812},"s4XuR","address",[43,815,816],{"class":49},":",[43,818,809],{"class":64},[43,820,744],{"class":812},[43,822,816],{"class":49},[43,824,825],{"class":53}," string",[43,827,828],{"class":64},"; ",[43,830,748],{"class":812},[43,832,816],{"class":49},[43,834,825],{"class":53},[43,836,828],{"class":64},[43,838,751],{"class":812},[43,840,816],{"class":49},[43,842,825],{"class":53},[43,844,845],{"class":64}," } }\n",[43,847,848,850,853,855,858,860,863,866,869],{"class":45,"line":124},[43,849,580],{"class":49},[43,851,852],{"class":53}," ctx",[43,854,57],{"class":49},[43,856,857],{"class":60}," injectForm",[43,859,394],{"class":64},[43,861,862],{"class":60},"SignupForm",[43,864,865],{"class":64},">(",[43,867,868],{"class":68},"'signup'",[43,870,121],{"class":64},[43,872,873,875,877],{"class":45,"line":140},[43,874,432],{"class":64},[43,876,398],{"class":397},[43,878,413],{"class":64},[43,880,881],{"class":45,"line":452},[43,882,85],{"emptyLinePlaceholder":84},[43,884,885,887,889],{"class":45,"line":472},[43,886,394],{"class":64},[43,888,447],{"class":397},[43,890,413],{"class":64},[43,892,893,895,897,900,902,905],{"class":45,"line":630},[43,894,455],{"class":64},[43,896,617],{"class":397},[43,898,899],{"class":60}," v-if",[43,901,407],{"class":64},[43,903,904],{"class":68},"\"ctx\"",[43,906,413],{"class":64},[43,908,909,911,913,915,917,920],{"class":45,"line":647},[43,910,633],{"class":64},[43,912,458],{"class":397},[43,914,498],{"class":60},[43,916,407],{"class":64},[43,918,919],{"class":68},"\"ctx.register('address.street')\"",[43,921,469],{"class":64},[43,923,924,926,928,930,932,935],{"class":45,"line":657},[43,925,633],{"class":64},[43,927,458],{"class":397},[43,929,498],{"class":60},[43,931,407],{"class":64},[43,933,934],{"class":68},"\"ctx.register('address.city')\"",[43,936,469],{"class":64},[43,938,940,942,944,946,948,951],{"class":45,"line":939},12,[43,941,633],{"class":64},[43,943,458],{"class":397},[43,945,498],{"class":60},[43,947,407],{"class":64},[43,949,950],{"class":68},"\"ctx.register('address.zip')\"",[43,952,469],{"class":64},[43,954,956,958,960],{"class":45,"line":955},13,[43,957,650],{"class":64},[43,959,617],{"class":397},[43,961,413],{"class":64},[43,963,965,967,969],{"class":45,"line":964},14,[43,966,432],{"class":64},[43,968,447],{"class":397},[43,970,413],{"class":64},[14,972,973,975,976,978,979,982],{},[23,974,710],{}," is a single-purpose ambient hook — it never accepts a\nkey or path. Compound use-cases belong on ",[23,977,734],{},", which\nalready handles typed sub-paths, structured paths, ",[23,980,981],{},"fields",",\nand the rest.",[356,984,986,987,990],{"id":985},"_4-assignkey-low-level-escape-hatch","4. ",[23,988,989],{},"assignKey"," low-level escape hatch",[14,992,993],{},"For Web Components (real custom elements that aren't Vue\ncomponents) or unusual binding targets, install the assigner\ndirectly on the element:",[34,995,997],{"className":36,"code":996,"language":38,"meta":39,"style":39},"import { assignKey } from 'attaform'\nelRef.value[assignKey] = (newValue) => emit('update:modelValue', newValue)\n",[23,998,999,1011],{"__ignoreMap":39},[43,1000,1001,1004,1007,1009],{"class":45,"line":46},[43,1002,1003],{"class":49},"import",[43,1005,1006],{"class":64}," { assignKey } ",[43,1008,572],{"class":49},[43,1010,575],{"class":68},[43,1012,1013,1016,1018,1021,1024,1027,1030,1033,1035,1038],{"class":45,"line":81},[43,1014,1015],{"class":64},"elRef.value[assignKey] ",[43,1017,407],{"class":49},[43,1019,1020],{"class":64}," (",[43,1022,1023],{"class":812},"newValue",[43,1025,1026],{"class":64},") ",[43,1028,1029],{"class":49},"=>",[43,1031,1032],{"class":60}," emit",[43,1034,115],{"class":64},[43,1036,1037],{"class":68},"'update:modelValue'",[43,1039,1040],{"class":64},", newValue)\n",[14,1042,1043,1044,1047,1048,1051,1052,1054,1055,1057],{},"A companion directive ordered first in ",[23,1045,1046],{},"withDirectives"," lets the\nassigner land before ",[23,1049,1050],{},"vRegister.created"," runs, suppressing the\nunsupported-element warn. The directive also respects a pre-\ninstalled ",[23,1053,989],{}," and won't clobber it. Use this only when\n",[23,1056,710],{}," doesn't fit (typically Web Components).",[356,1059,1061],{"id":1060},"dev-warn","Dev-warn",[14,1063,1064,1065,1067,1068,1070],{},"The first time the directive sees a non-input \u002F select \u002F textarea\nroot WITHOUT a ",[23,1066,710],{}," sentinel and WITHOUT an ",[23,1069,989],{},"\noverride, it logs a one-shot warning pointing at this recipe.",[18,1072,1074],{"id":1073},"dev-mode-warnings","Dev-mode warnings",[14,1076,1077],{},"Two symmetric warnings catch \"wired half the pipeline\" footguns\n(once per form in dev, silenced in production):",[148,1079,1080,1088],{},[151,1081,1082,1087],{},[294,1083,1084,1086],{},[23,1085,176],{}," configured but no field opts in"," — drafts never save.",[151,1089,1090,1099],{},[294,1091,1092,1095,1096,1098],{},[23,1093,1094],{},"register({ persist: true })"," but no ",[23,1097,176],{}," on the form"," —\nopt-ins recorded, no writes land.",[14,1101,1102],{},"The warnings include the form key and (where applicable) the path\nthat triggered them.",[18,1104,1106],{"id":1105},"gotchas","Gotchas",[148,1108,1109,1120,1134,1140],{},[151,1110,1111,1116,1117,170],{},[294,1112,1113,1115],{},[23,1114,291],{}," blocks the main thread"," on large writes. If\nyour writes exceed ~50 ms on a cold device, switch to\n",[23,1118,1119],{},"'indexeddb'",[151,1121,1122,1125,1126,1129,1130,1133],{},[294,1123,1124],{},"Safari private mode"," can throw ",[23,1127,1128],{},"SecurityError"," on\n",[23,1131,1132],{},"localStorage.setItem",". The adapter swallows it — the form stays\nusable; writes just don't land. See the dev-warning section\nabove.",[151,1135,1136,1139],{},[294,1137,1138],{},"Re-mounting an opted-in input"," with a fresh DOM element issues\na new element ID; the prior opt-in (tied to the old element's ID)\nwas already removed at unmount. Rapid mount\u002Funmount cycles are\nfine — the registry tracks elements via WeakMap, which auto-GCs\nwhen the DOM node is dropped.",[151,1141,1142,1148,1149,1152],{},[294,1143,1144,1147],{},[23,1145,1146],{},"acknowledgeSensitive: true"," is a code-review trigger, not a\nsoundness boundary."," It silences the throw for paths that match\nthe sensitive-name heuristic, but the heuristic doesn't catch\nalias-typed paths (",[23,1150,1151],{},"register('pswd' as 'password')","), abbreviated\nvariants not in the list, or schemas with deliberately innocuous\nkeys for sensitive data. Treat the override as an explicit\ndecision worth a second pair of eyes; don't treat its absence\nas a security guarantee.",[18,1154,1156],{"id":1155},"see-also","See also",[148,1158,1159,1167,1174],{},[151,1160,1161,1166],{},[1162,1163,1165],"a",{"href":1164},"\u002Fdocs\u002Frecipes\u002Fpersistence","Persistence walkthrough"," — the basics",[151,1168,1169,1173],{},[1162,1170,1172],{"href":1171},"\u002Fdocs\u002Frecipes\u002Fpersistence-policy","Persistence policy"," — what gets stored, schema-change invalidation",[151,1175,1176,1180],{},[1162,1177,1179],{"href":1178},"\u002Fdocs\u002Frecipes\u002Fpersistence-backends","Persistence backends"," — picking and configuring storage",[1182,1183,1184],"style",{},"html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .s9eBZ, html code.shiki .s9eBZ{--shiki-default:#22863A;--shiki-dark:#85E89D}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}",{"title":39,"searchDepth":81,"depth":81,"links":1186},[1187,1189,1191,1192,1193,1194,1195,1205,1206,1207],{"id":20,"depth":81,"text":1188},"Imperative checkpoint via form.persist()",{"id":180,"depth":81,"text":1190},"Wiping a draft via form.clearPersistedDraft()",{"id":240,"depth":81,"text":241},{"id":274,"depth":81,"text":275},{"id":285,"depth":81,"text":286},{"id":326,"depth":81,"text":327},{"id":344,"depth":81,"text":345,"children":1196},[1197,1198,1200,1202,1204],{"id":358,"depth":88,"text":359},{"id":521,"depth":88,"text":1199},"2. Non-form root → useRegister() (recommended)",{"id":730,"depth":88,"text":1201},"3. Compound components → injectForm",{"id":985,"depth":88,"text":1203},"4. assignKey low-level escape hatch",{"id":1060,"depth":88,"text":1061},{"id":1073,"depth":81,"text":1074},{"id":1105,"depth":81,"text":1106},{"id":1155,"depth":81,"text":1156},"md",{},"\u002Fdocs\u002Frecipes\u002Fpersistence-edge-cases",{"title":5,"description":16},"docs\u002Frecipes\u002Fpersistence-edge-cases","SZiKDp5hDjJRvvClXkCGXG5UAmOm1HoMyQnHlr8Vcfo",1777934136587]