[{"data":1,"prerenderedAt":931},["ShallowReactive",2],{"content-\u002Fdocs\u002Freading-the-form\u002Fmeta":3},{"id":4,"title":5,"body":6,"description":910,"extension":911,"meta":912,"metaRows":913,"navigation":925,"path":926,"seo":927,"source":928,"stem":929,"__hash__":930},"docs\u002Fdocs\u002Freading-the-form\u002Fmeta.md","meta",{"type":7,"value":8,"toc":901},"minimark",[9,15,22,25,61,65,70,83,93,103,152,155,161,317,321,324,384,387,443,449,487,490,527,531,547,560,567,639,642,659,679,692,772,778,781,794,854,857,861,897],[10,11,12],"h1",{"id":5},[13,14,5],"code",{},[16,17,18],"blockquote",{},[19,20,21],"p",{},"Form-level state in one place: every FieldState bit rolled up across paths, plus the seven form-only reads for the submit cycle and wizard departures.",[23,24],"docs-meta-table",{},[19,26,27,28,31,32,35,36,39,40,42,43,46,47,49,50,55,56,60],{},"Submit the demo without changing the simulate-failure toggle to watch ",[13,29,30],{},"submitting"," flip true mid-await, ",[13,33,34],{},"submissionAttempts"," increment, and ",[13,37,38],{},"submitted"," flip true once the callback resolves. Flip the toggle and submit again: ",[13,41,34],{}," still increments and ",[13,44,45],{},"submitError"," populates with the rejected callback's message, but ",[13,48,38],{}," stays false because the callback never resolved. The ",[51,52,54],"a",{"href":53},"#form-only-properties","Form-only properties"," section below names every bit; the inherited FieldState aggregations ",[51,57,59],{"href":58},"\u002Fdocs\u002Freading-the-form\u002Ffields","link forward to the fields page",".",[62,63],"docs-demo",{"label":64,"slug":5},"Meta Demo",[66,67,69],"h2",{"id":68},"two-halves","Two halves",[19,71,72,75,76,79,80,82],{},[13,73,74],{},"form.meta"," extends ",[13,77,78],{},"FieldState"," with seven form-only properties. That means ",[13,81,5],{}," has 36 reads total:",[84,85,86,90],"ul",{},[87,88,89],"li",{},"29 properties inherited from FieldState, aggregated across every leaf in the form.",[87,91,92],{},"7 form-only properties that describe the submit cycle and the wizard-departure counter.",[19,94,95,96,102],{},"The inherited bits are documented once on the ",[51,97,98,101],{"href":58},[13,99,100],{},"fields"," page",": same property names, same types, same reactivity. The only difference is the aggregation:",[104,105,110],"pre",{"className":106,"code":107,"language":108,"meta":109,"style":109},"language-ts shiki shiki-themes github-light github-dark","form.fields.email.dirty \u002F\u002F this one field\nform.meta.dirty \u002F\u002F any field in the form\nform.meta.errors \u002F\u002F every error across every path\nform.meta.value \u002F\u002F the full form values object\n","ts","",[13,111,112,125,134,143],{"__ignoreMap":109},[113,114,117,121],"span",{"class":115,"line":116},"line",1,[113,118,120],{"class":119},"sVt8B","form.fields.email.dirty ",[113,122,124],{"class":123},"sJ8bj","\u002F\u002F this one field\n",[113,126,128,131],{"class":115,"line":127},2,[113,129,130],{"class":119},"form.meta.dirty ",[113,132,133],{"class":123},"\u002F\u002F any field in the form\n",[113,135,137,140],{"class":115,"line":136},3,[113,138,139],{"class":119},"form.meta.errors ",[113,141,142],{"class":123},"\u002F\u002F every error across every path\n",[113,144,146,149],{"class":115,"line":145},4,[113,147,148],{"class":119},"form.meta.value ",[113,150,151],{"class":123},"\u002F\u002F the full form values object\n",[66,153,54],{"id":154},"form-only-properties",[19,156,157,158,160],{},"These seven reads exist only on ",[13,159,5],{},", not on individual FieldStates.",[162,163,164,180],"table",{},[165,166,167],"thead",{},[168,169,170,174,177],"tr",{},[171,172,173],"th",{},"Property",[171,175,176],{},"Type",[171,178,179],{},"Meaning",[181,182,183,205,219,233,251,273,298],"tbody",{},[168,184,185,190,195],{},[186,187,188],"td",{},[13,189,30],{},[186,191,192],{},[13,193,194],{},"boolean",[186,196,197,200,201,204],{},[13,198,199],{},"true"," while a ",[13,202,203],{},"handleSubmit","-produced handler is running. Covers both the validation phase and the async callback.",[168,206,207,211,216],{},[186,208,209],{},[13,210,34],{},[186,212,213],{},[13,214,215],{},"number",[186,217,218],{},"How many times the handler has been invoked (pass or fail). Useful for \"show errors after first submit\" UX.",[168,220,221,226,230],{},[186,222,223],{},[13,224,225],{},"departAttempts",[186,227,228],{},[13,229,215],{},[186,231,232],{},"How many times wizard navigation has actually departed this form. Bumps on real departures only (no-op back \u002F same-key goTo \u002F blocked next stay put).",[168,234,235,239,244],{},[186,236,237],{},[13,238,45],{},[186,240,241],{},[13,242,243],{},"unknown",[186,245,246,247,250],{},"The error from the most recent callback rejection. ",[13,248,249],{},"null"," on success and at the start of each new attempt.",[168,252,253,258,262],{},[186,254,255],{},[13,256,257],{},"errorCount",[186,259,260],{},[13,261,215],{},[186,263,264,265,268,269,272],{},"Scalar mirror of ",[13,266,267],{},"errors.length",". Read it from templates and ",[13,270,271],{},"watch()"," without indexing the array.",[168,274,275,279,283],{},[186,276,277],{},[13,278,38],{},[186,280,281],{},[13,282,194],{},[186,284,285,287,288,290,291,294,295,60],{},[13,286,199],{}," once a ",[13,289,203],{}," callback has resolved without throwing. Failed submits leave it ",[13,292,293],{},"false",". Zeroed by ",[13,296,297],{},"form.reset()",[168,299,300,305,310],{},[186,301,302],{},[13,303,304],{},"instanceId",[186,306,307],{},[13,308,309],{},"string",[186,311,312,313,316],{},"Per-",[13,314,315],{},"useForm()","-call identity, stable for the lifetime of one call. New on every fresh mount.",[66,318,320],{"id":319},"templates","Templates",[19,322,323],{},"The classic submit-button pattern reads two bits:",[104,325,329],{"className":326,"code":327,"language":328,"meta":109,"style":109},"language-vue shiki shiki-themes github-light github-dark","\u003Cbutton :disabled=\"form.meta.submitting\" type=\"submit\">\n  {{ form.meta.submitting ? 'Saving…' : 'Save' }}\n\u003C\u002Fbutton>\n","vue",[13,330,331,370,375],{"__ignoreMap":109},[113,332,333,336,340,343,347,350,354,357,359,362,364,367],{"class":115,"line":116},[113,334,335],{"class":119},"\u003C",[113,337,339],{"class":338},"s9eBZ","button",[113,341,342],{"class":119}," :",[113,344,346],{"class":345},"sScJk","disabled",[113,348,349],{"class":119},"=",[113,351,353],{"class":352},"sZZnC","\"",[113,355,356],{"class":119},"form.meta.submitting",[113,358,353],{"class":352},[113,360,361],{"class":345}," type",[113,363,349],{"class":119},[113,365,366],{"class":352},"\"submit\"",[113,368,369],{"class":119},">\n",[113,371,372],{"class":115,"line":127},[113,373,374],{"class":119},"  {{ form.meta.submitting ? 'Saving…' : 'Save' }}\n",[113,376,377,380,382],{"class":115,"line":136},[113,378,379],{"class":119},"\u003C\u002F",[113,381,339],{"class":338},[113,383,369],{"class":119},[19,385,386],{},"The \"show errors after first submit attempt\" pattern reads the counter so failed attempts count:",[104,388,390],{"className":326,"code":389,"language":328,"meta":109,"style":109},"\u003Cp v-if=\"form.meta.submissionAttempts > 0 && form.meta.errorCount > 0\">\n  {{ form.meta.errorCount }} field(s) need attention.\n\u003C\u002Fp>\n",[13,391,392,430,435],{"__ignoreMap":109},[113,393,394,396,398,402,404,406,409,412,416,419,422,424,426,428],{"class":115,"line":116},[113,395,335],{"class":119},[113,397,19],{"class":338},[113,399,401],{"class":400},"szBVR"," v-if",[113,403,349],{"class":119},[113,405,353],{"class":352},[113,407,408],{"class":119},"form.meta.submissionAttempts ",[113,410,411],{"class":400},">",[113,413,415],{"class":414},"sj4cs"," 0",[113,417,418],{"class":400}," &&",[113,420,421],{"class":119}," form.meta.errorCount ",[113,423,411],{"class":400},[113,425,415],{"class":414},[113,427,353],{"class":352},[113,429,369],{"class":119},[113,431,432],{"class":115,"line":127},[113,433,434],{"class":119},"  {{ form.meta.errorCount }} field(s) need attention.\n",[113,436,437,439,441],{"class":115,"line":136},[113,438,379],{"class":119},[113,440,19],{"class":338},[113,442,369],{"class":119},[19,444,445,446,448],{},"The \"post-success confirmation\" pattern reads ",[13,447,38],{}," instead, so the banner only renders after the callback actually succeeded:",[104,450,452],{"className":326,"code":451,"language":328,"meta":109,"style":109},"\u003Cp v-if=\"form.meta.submitted && !form.meta.dirty\">All saved.\u003C\u002Fp>\n",[13,453,454],{"__ignoreMap":109},[113,455,456,458,460,462,464,466,469,472,475,478,480,483,485],{"class":115,"line":116},[113,457,335],{"class":119},[113,459,19],{"class":338},[113,461,401],{"class":400},[113,463,349],{"class":119},[113,465,353],{"class":352},[113,467,468],{"class":119},"form.meta.submitted ",[113,470,471],{"class":400},"&&",[113,473,474],{"class":400}," !",[113,476,477],{"class":119},"form.meta.dirty",[113,479,353],{"class":352},[113,481,482],{"class":119},">All saved.\u003C\u002F",[113,484,19],{"class":338},[113,486,369],{"class":119},[19,488,489],{},"The form-summary pattern reads three:",[104,491,493],{"className":326,"code":492,"language":328,"meta":109,"style":109},"\u003Cp>\n  {{ form.meta.dirty ? 'Unsaved changes' : 'No changes' }} ·\n  {{ form.meta.valid ? 'Ready to submit' : `${form.meta.errorCount} error(s)` }} ·\n  Submitted {{ form.meta.submissionAttempts }} time(s)\n\u003C\u002Fp>\n",[13,494,495,503,508,513,518],{"__ignoreMap":109},[113,496,497,499,501],{"class":115,"line":116},[113,498,335],{"class":119},[113,500,19],{"class":338},[113,502,369],{"class":119},[113,504,505],{"class":115,"line":127},[113,506,507],{"class":119},"  {{ form.meta.dirty ? 'Unsaved changes' : 'No changes' }} ·\n",[113,509,510],{"class":115,"line":136},[113,511,512],{"class":119},"  {{ form.meta.valid ? 'Ready to submit' : `${form.meta.errorCount} error(s)` }} ·\n",[113,514,515],{"class":115,"line":145},[113,516,517],{"class":119},"  Submitted {{ form.meta.submissionAttempts }} time(s)\n",[113,519,521,523,525],{"class":115,"line":520},5,[113,522,379],{"class":119},[113,524,19],{"class":338},[113,526,369],{"class":119},[66,528,530],{"id":529},"submiterror-lifecycle","submitError lifecycle",[19,532,533,535,536,538,539,542,543,546],{},[13,534,45],{}," mirrors what the callback threw or rejected with. ",[13,537,203],{}," catches the throw, routes it through ",[13,540,541],{},"onError",", and writes it to ",[13,544,545],{},"form.meta.submitError"," for reactive read-out.",[84,548,549,554,557],{},[87,550,551,553],{},[13,552,249],{}," at form mount, between attempts, and on success.",[87,555,556],{},"Set to the thrown \u002F rejected value on callback failure.",[87,558,559],{},"Cleared at the start of the next submit attempt.",[19,561,562,563,566],{},"Reach for it when an inline failure banner needs to react to submit errors without your own ",[13,564,565],{},"try { await onSubmit() }"," wrapper:",[104,568,570],{"className":326,"code":569,"language":328,"meta":109,"style":109},"\u003Cp v-if=\"form.meta.submitError\" class=\"error\">\n  Submission failed:\n  {{\n    form.meta.submitError instanceof Error\n      ? form.meta.submitError.message\n      : String(form.meta.submitError)\n  }}\n\u003C\u002Fp>\n",[13,571,572,598,603,608,613,618,624,630],{"__ignoreMap":109},[113,573,574,576,578,580,582,584,586,588,591,593,596],{"class":115,"line":116},[113,575,335],{"class":119},[113,577,19],{"class":338},[113,579,401],{"class":400},[113,581,349],{"class":119},[113,583,353],{"class":352},[113,585,545],{"class":119},[113,587,353],{"class":352},[113,589,590],{"class":345}," class",[113,592,349],{"class":119},[113,594,595],{"class":352},"\"error\"",[113,597,369],{"class":119},[113,599,600],{"class":115,"line":127},[113,601,602],{"class":119},"  Submission failed:\n",[113,604,605],{"class":115,"line":136},[113,606,607],{"class":119},"  {{\n",[113,609,610],{"class":115,"line":145},[113,611,612],{"class":119},"    form.meta.submitError instanceof Error\n",[113,614,615],{"class":115,"line":520},[113,616,617],{"class":119},"      ? form.meta.submitError.message\n",[113,619,621],{"class":115,"line":620},6,[113,622,623],{"class":119},"      : String(form.meta.submitError)\n",[113,625,627],{"class":115,"line":626},7,[113,628,629],{"class":119},"  }}\n",[113,631,633,635,637],{"class":115,"line":632},8,[113,634,379],{"class":119},[113,636,19],{"class":338},[113,638,369],{"class":119},[66,640,225],{"id":641},"departattempts",[19,643,644,646,647,650,651,654,655,658],{},[13,645,225],{}," counts how many times ",[13,648,649],{},"wizard.next",", ",[13,652,653],{},"wizard.back",", or ",[13,656,657],{},"wizard.goTo"," has actually left this form's step. The counter bumps on real departures only:",[84,660,661,667,673],{},[87,662,663,666],{},[13,664,665],{},"back()"," from the first step is a no-op and leaves it alone.",[87,668,669,672],{},[13,670,671],{},"goTo(currentKey)"," (same-key jump) leaves it alone.",[87,674,675,678],{},[13,676,677],{},"next()"," blocked by failed activation leaves it alone.",[19,680,681,682,685,686,688,689,691],{},"The counter is a pure read; Attaform's default ",[13,683,684],{},"getDisplayState"," heuristic runs off ",[13,687,34],{}," instead. Reach for ",[13,690,225],{}," when an analytics event, a prior-step badge, or a layered error-reveal predicate wants the \"user visited and left\" signal:",[104,693,695],{"className":106,"code":694,"language":108,"meta":109,"style":109},"watch(\n  () => form.meta.departAttempts,\n  (count) => {\n    if (count === 1) analytics.track('step_first_departure', { form: form.key })\n  }\n)\n",[13,696,697,705,716,733,762,767],{"__ignoreMap":109},[113,698,699,702],{"class":115,"line":116},[113,700,701],{"class":345},"watch",[113,703,704],{"class":119},"(\n",[113,706,707,710,713],{"class":115,"line":127},[113,708,709],{"class":119},"  () ",[113,711,712],{"class":400},"=>",[113,714,715],{"class":119}," form.meta.departAttempts,\n",[113,717,718,721,725,728,730],{"class":115,"line":136},[113,719,720],{"class":119},"  (",[113,722,724],{"class":723},"s4XuR","count",[113,726,727],{"class":119},") ",[113,729,712],{"class":400},[113,731,732],{"class":119}," {\n",[113,734,735,738,741,744,747,750,753,756,759],{"class":115,"line":145},[113,736,737],{"class":400},"    if",[113,739,740],{"class":119}," (count ",[113,742,743],{"class":400},"===",[113,745,746],{"class":414}," 1",[113,748,749],{"class":119},") analytics.",[113,751,752],{"class":345},"track",[113,754,755],{"class":119},"(",[113,757,758],{"class":352},"'step_first_departure'",[113,760,761],{"class":119},", { form: form.key })\n",[113,763,764],{"class":115,"line":520},[113,765,766],{"class":119},"  }\n",[113,768,769],{"class":115,"line":620},[113,770,771],{"class":119},")\n",[19,773,774,775,777],{},"Cleared by ",[13,776,297],{}," alongside the submission counters.",[66,779,304],{"id":780},"instanceid",[19,782,783,785,786,789,790,793],{},[13,784,304],{}," distinguishes two mounts of the same shared form. Two ",[13,787,788],{},"useForm({ key: 'signup' })"," calls return the same FormStore (so writes in one reflect in the other), but ",[13,791,792],{},"form.meta.instanceId"," differs. Useful when devtools, telemetry, or e2e selectors need to disambiguate which mount triggered an event.",[104,795,797],{"className":326,"code":796,"language":328,"meta":109,"style":109},"\u003Cform :data-form-id=\"form.meta.instanceId\" @submit.prevent=\"onSubmit\">\n  …\n\u003C\u002Fform>\n",[13,798,799,841,846],{"__ignoreMap":109},[113,800,801,803,806,808,811,813,815,817,819,822,825,827,830,832,834,837,839],{"class":115,"line":116},[113,802,335],{"class":119},[113,804,805],{"class":338},"form",[113,807,342],{"class":119},[113,809,810],{"class":345},"data-form-id",[113,812,349],{"class":119},[113,814,353],{"class":352},[113,816,792],{"class":119},[113,818,353],{"class":352},[113,820,821],{"class":119}," @",[113,823,824],{"class":345},"submit",[113,826,60],{"class":119},[113,828,829],{"class":345},"prevent",[113,831,349],{"class":119},[113,833,353],{"class":352},[113,835,836],{"class":119},"onSubmit",[113,838,353],{"class":352},[113,840,369],{"class":119},[113,842,843],{"class":115,"line":127},[113,844,845],{"class":119},"  …\n",[113,847,848,850,852],{"class":115,"line":136},[113,849,379],{"class":119},[113,851,805],{"class":338},[113,853,369],{"class":119},[19,855,856],{},"Treat as identity, not state: don't parse it, don't compare ordinally, don't persist.",[66,858,860],{"id":859},"where-to-next","Where to next",[84,862,863,873,888],{},[87,864,865,869,870,872],{},[51,866,867],{"href":58},[13,868,100],{},": the per-leaf FieldState, including every property ",[13,871,5],{}," inherits.",[87,874,875,880,881,650,883,885,886,60],{},[51,876,878],{"href":877},"\u002Fdocs\u002Fsubmitting\u002Fhandle-submit",[13,879,203],{},": the dispatch surface that drives ",[13,882,30],{},[13,884,34],{},", and ",[13,887,45],{},[87,889,890,894,895,60],{},[51,891,893],{"href":892},"\u002Fdocs\u002Freading-the-form\u002Fthe-form","The form",": the full reactive surface that surrounds ",[13,896,5],{},[898,899,900],"style",{},"html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}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 .s9eBZ, html code.shiki .s9eBZ{--shiki-default:#22863A;--shiki-dark:#85E89D}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}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 .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}",{"title":109,"searchDepth":127,"depth":127,"links":902},[903,904,905,906,907,908,909],{"id":68,"depth":127,"text":69},{"id":154,"depth":127,"text":54},{"id":319,"depth":127,"text":320},{"id":529,"depth":127,"text":530},{"id":641,"depth":127,"text":225},{"id":780,"depth":127,"text":304},{"id":859,"depth":127,"text":860},"form.meta is the form-level FieldState aggregation plus seven form-only reads, submitting, submissionAttempts, departAttempts, submitError, errorCount, submitted, and instanceId.","md",{},[914,917,919,922],{"label":915,"value":916},"Category","Return property",{"label":176,"value":918,"kind":13},"FormMeta\u003CForm>",{"label":920,"value":921},"Reactive","Yes",{"label":923,"value":924},"Shape","FieldState aggregation + 7 form-only props",true,"\u002Fdocs\u002Freading-the-form\u002Fmeta",{"title":5,"description":910},null,"docs\u002Freading-the-form\u002Fmeta","HR8LDhlopN84GICQxi3EU0snTTYymKO_3bCnx3CiwpY",1780949758672]