[{"data":1,"prerenderedAt":939},["ShallowReactive",2],{"content-\u002Fdocs\u002Freading-the-form\u002Fmeta":3},{"id":4,"title":5,"body":6,"description":918,"extension":919,"meta":920,"metaRows":921,"navigation":933,"path":934,"seo":935,"source":936,"stem":937,"__hash__":938},"docs\u002Fdocs\u002Freading-the-form\u002Fmeta.md","meta",{"type":7,"value":8,"toc":909},"minimark",[9,15,22,25,61,65,70,83,93,103,152,155,161,321,325,328,388,391,447,457,495,498,535,539,555,568,575,647,650,667,687,700,780,786,789,802,862,865,869,905],[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 succeeds. 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,302],"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,298,299,60],{},[13,286,199],{}," once a ",[13,289,203],{}," callback resolves without throwing and without leaving errors set. Failed submits, including a ",[13,292,293],{},"setErrors(...); return",", leave it ",[13,296,297],{},"false",". Zeroed by ",[13,300,301],{},"form.reset()",[168,303,304,309,314],{},[186,305,306],{},[13,307,308],{},"instanceId",[186,310,311],{},[13,312,313],{},"string",[186,315,316,317,320],{},"Per-",[13,318,319],{},"useForm()","-call identity, stable for the lifetime of one call. New on every fresh mount.",[66,322,324],{"id":323},"templates","Templates",[19,326,327],{},"The classic submit-button pattern reads two bits:",[104,329,333],{"className":330,"code":331,"language":332,"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,334,335,374,379],{"__ignoreMap":109},[113,336,337,340,344,347,351,354,358,361,363,366,368,371],{"class":115,"line":116},[113,338,339],{"class":119},"\u003C",[113,341,343],{"class":342},"s9eBZ","button",[113,345,346],{"class":119}," :",[113,348,350],{"class":349},"sScJk","disabled",[113,352,353],{"class":119},"=",[113,355,357],{"class":356},"sZZnC","\"",[113,359,360],{"class":119},"form.meta.submitting",[113,362,357],{"class":356},[113,364,365],{"class":349}," type",[113,367,353],{"class":119},[113,369,370],{"class":356},"\"submit\"",[113,372,373],{"class":119},">\n",[113,375,376],{"class":115,"line":127},[113,377,378],{"class":119},"  {{ form.meta.submitting ? 'Saving…' : 'Save' }}\n",[113,380,381,384,386],{"class":115,"line":136},[113,382,383],{"class":119},"\u003C\u002F",[113,385,343],{"class":342},[113,387,373],{"class":119},[19,389,390],{},"The \"show errors after first submit attempt\" pattern reads the counter so failed attempts count:",[104,392,394],{"className":330,"code":393,"language":332,"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,395,396,434,439],{"__ignoreMap":109},[113,397,398,400,402,406,408,410,413,416,420,423,426,428,430,432],{"class":115,"line":116},[113,399,339],{"class":119},[113,401,19],{"class":342},[113,403,405],{"class":404},"szBVR"," v-if",[113,407,353],{"class":119},[113,409,357],{"class":356},[113,411,412],{"class":119},"form.meta.submissionAttempts ",[113,414,415],{"class":404},">",[113,417,419],{"class":418},"sj4cs"," 0",[113,421,422],{"class":404}," &&",[113,424,425],{"class":119}," form.meta.errorCount ",[113,427,415],{"class":404},[113,429,419],{"class":418},[113,431,357],{"class":356},[113,433,373],{"class":119},[113,435,436],{"class":115,"line":127},[113,437,438],{"class":119},"  {{ form.meta.errorCount }} field(s) need attention.\n",[113,440,441,443,445],{"class":115,"line":136},[113,442,383],{"class":119},[113,444,19],{"class":342},[113,446,373],{"class":119},[19,448,449,450,452,453,456],{},"The \"post-success confirmation\" pattern reads ",[13,451,38],{}," instead, so the banner only renders after the callback actually succeeded. A callback that hands a server rejection to ",[13,454,455],{},"setErrors"," and returns counts as a failed submit, so the banner stays hidden:",[104,458,460],{"className":330,"code":459,"language":332,"meta":109,"style":109},"\u003Cp v-if=\"form.meta.submitted && !form.meta.dirty\">All saved.\u003C\u002Fp>\n",[13,461,462],{"__ignoreMap":109},[113,463,464,466,468,470,472,474,477,480,483,486,488,491,493],{"class":115,"line":116},[113,465,339],{"class":119},[113,467,19],{"class":342},[113,469,405],{"class":404},[113,471,353],{"class":119},[113,473,357],{"class":356},[113,475,476],{"class":119},"form.meta.submitted ",[113,478,479],{"class":404},"&&",[113,481,482],{"class":404}," !",[113,484,485],{"class":119},"form.meta.dirty",[113,487,357],{"class":356},[113,489,490],{"class":119},">All saved.\u003C\u002F",[113,492,19],{"class":342},[113,494,373],{"class":119},[19,496,497],{},"The form-summary pattern reads three:",[104,499,501],{"className":330,"code":500,"language":332,"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,502,503,511,516,521,526],{"__ignoreMap":109},[113,504,505,507,509],{"class":115,"line":116},[113,506,339],{"class":119},[113,508,19],{"class":342},[113,510,373],{"class":119},[113,512,513],{"class":115,"line":127},[113,514,515],{"class":119},"  {{ form.meta.dirty ? 'Unsaved changes' : 'No changes' }} ·\n",[113,517,518],{"class":115,"line":136},[113,519,520],{"class":119},"  {{ form.meta.valid ? 'Ready to submit' : `${form.meta.errorCount} error(s)` }} ·\n",[113,522,523],{"class":115,"line":145},[113,524,525],{"class":119},"  Submitted {{ form.meta.submissionAttempts }} time(s)\n",[113,527,529,531,533],{"class":115,"line":528},5,[113,530,383],{"class":119},[113,532,19],{"class":342},[113,534,373],{"class":119},[66,536,538],{"id":537},"submiterror-lifecycle","submitError lifecycle",[19,540,541,543,544,546,547,550,551,554],{},[13,542,45],{}," mirrors what the callback threw or rejected with. ",[13,545,203],{}," catches the throw, routes it through ",[13,548,549],{},"onError",", and writes it to ",[13,552,553],{},"form.meta.submitError"," for reactive read-out.",[84,556,557,562,565],{},[87,558,559,561],{},[13,560,249],{}," at form mount, between attempts, and on success.",[87,563,564],{},"Set to the thrown \u002F rejected value on callback failure.",[87,566,567],{},"Cleared at the start of the next submit attempt.",[19,569,570,571,574],{},"Reach for it when an inline failure banner needs to react to submit errors without your own ",[13,572,573],{},"try { await onSubmit() }"," wrapper:",[104,576,578],{"className":330,"code":577,"language":332,"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,579,580,606,611,616,621,626,632,638],{"__ignoreMap":109},[113,581,582,584,586,588,590,592,594,596,599,601,604],{"class":115,"line":116},[113,583,339],{"class":119},[113,585,19],{"class":342},[113,587,405],{"class":404},[113,589,353],{"class":119},[113,591,357],{"class":356},[113,593,553],{"class":119},[113,595,357],{"class":356},[113,597,598],{"class":349}," class",[113,600,353],{"class":119},[113,602,603],{"class":356},"\"error\"",[113,605,373],{"class":119},[113,607,608],{"class":115,"line":127},[113,609,610],{"class":119},"  Submission failed:\n",[113,612,613],{"class":115,"line":136},[113,614,615],{"class":119},"  {{\n",[113,617,618],{"class":115,"line":145},[113,619,620],{"class":119},"    form.meta.submitError instanceof Error\n",[113,622,623],{"class":115,"line":528},[113,624,625],{"class":119},"      ? form.meta.submitError.message\n",[113,627,629],{"class":115,"line":628},6,[113,630,631],{"class":119},"      : String(form.meta.submitError)\n",[113,633,635],{"class":115,"line":634},7,[113,636,637],{"class":119},"  }}\n",[113,639,641,643,645],{"class":115,"line":640},8,[113,642,383],{"class":119},[113,644,19],{"class":342},[113,646,373],{"class":119},[66,648,225],{"id":649},"departattempts",[19,651,652,654,655,658,659,662,663,666],{},[13,653,225],{}," counts how many times ",[13,656,657],{},"wizard.next",", ",[13,660,661],{},"wizard.back",", or ",[13,664,665],{},"wizard.goTo"," has actually left this form's step. The counter bumps on real departures only:",[84,668,669,675,681],{},[87,670,671,674],{},[13,672,673],{},"back()"," from the first step is a no-op and leaves it alone.",[87,676,677,680],{},[13,678,679],{},"goTo(currentKey)"," (same-key jump) leaves it alone.",[87,682,683,686],{},[13,684,685],{},"next()"," blocked by failed activation leaves it alone.",[19,688,689,690,693,694,696,697,699],{},"The counter is a pure read; Attaform's default ",[13,691,692],{},"getDisplayState"," heuristic runs off ",[13,695,34],{}," instead. Reach for ",[13,698,225],{}," when an analytics event, a prior-step badge, or a layered error-reveal predicate wants the \"user visited and left\" signal:",[104,701,703],{"className":106,"code":702,"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,704,705,713,724,741,770,775],{"__ignoreMap":109},[113,706,707,710],{"class":115,"line":116},[113,708,709],{"class":349},"watch",[113,711,712],{"class":119},"(\n",[113,714,715,718,721],{"class":115,"line":127},[113,716,717],{"class":119},"  () ",[113,719,720],{"class":404},"=>",[113,722,723],{"class":119}," form.meta.departAttempts,\n",[113,725,726,729,733,736,738],{"class":115,"line":136},[113,727,728],{"class":119},"  (",[113,730,732],{"class":731},"s4XuR","count",[113,734,735],{"class":119},") ",[113,737,720],{"class":404},[113,739,740],{"class":119}," {\n",[113,742,743,746,749,752,755,758,761,764,767],{"class":115,"line":145},[113,744,745],{"class":404},"    if",[113,747,748],{"class":119}," (count ",[113,750,751],{"class":404},"===",[113,753,754],{"class":418}," 1",[113,756,757],{"class":119},") analytics.",[113,759,760],{"class":349},"track",[113,762,763],{"class":119},"(",[113,765,766],{"class":356},"'step_first_departure'",[113,768,769],{"class":119},", { form: form.key })\n",[113,771,772],{"class":115,"line":528},[113,773,774],{"class":119},"  }\n",[113,776,777],{"class":115,"line":628},[113,778,779],{"class":119},")\n",[19,781,782,783,785],{},"Cleared by ",[13,784,301],{}," alongside the submission counters.",[66,787,308],{"id":788},"instanceid",[19,790,791,793,794,797,798,801],{},[13,792,308],{}," distinguishes two mounts of the same shared form. Two ",[13,795,796],{},"useForm({ key: 'signup' })"," calls return the same FormStore (so writes in one reflect in the other), but ",[13,799,800],{},"form.meta.instanceId"," differs. Useful when devtools, telemetry, or e2e selectors need to disambiguate which mount triggered an event.",[104,803,805],{"className":330,"code":804,"language":332,"meta":109,"style":109},"\u003Cform :data-form-id=\"form.meta.instanceId\" @submit.prevent=\"onSubmit\">\n  …\n\u003C\u002Fform>\n",[13,806,807,849,854],{"__ignoreMap":109},[113,808,809,811,814,816,819,821,823,825,827,830,833,835,838,840,842,845,847],{"class":115,"line":116},[113,810,339],{"class":119},[113,812,813],{"class":342},"form",[113,815,346],{"class":119},[113,817,818],{"class":349},"data-form-id",[113,820,353],{"class":119},[113,822,357],{"class":356},[113,824,800],{"class":119},[113,826,357],{"class":356},[113,828,829],{"class":119}," @",[113,831,832],{"class":349},"submit",[113,834,60],{"class":119},[113,836,837],{"class":349},"prevent",[113,839,353],{"class":119},[113,841,357],{"class":356},[113,843,844],{"class":119},"onSubmit",[113,846,357],{"class":356},[113,848,373],{"class":119},[113,850,851],{"class":115,"line":127},[113,852,853],{"class":119},"  …\n",[113,855,856,858,860],{"class":115,"line":136},[113,857,383],{"class":119},[113,859,813],{"class":342},[113,861,373],{"class":119},[19,863,864],{},"Treat as identity, not state: don't parse it, don't compare ordinally, don't persist.",[66,866,868],{"id":867},"where-to-next","Where to next",[84,870,871,881,896],{},[87,872,873,877,878,880],{},[51,874,875],{"href":58},[13,876,100],{},": the per-leaf FieldState, including every property ",[13,879,5],{}," inherits.",[87,882,883,888,889,658,891,893,894,60],{},[51,884,886],{"href":885},"\u002Fdocs\u002Fsubmitting\u002Fhandle-submit",[13,887,203],{},": the dispatch surface that drives ",[13,890,30],{},[13,892,34],{},", and ",[13,895,45],{},[87,897,898,902,903,60],{},[51,899,901],{"href":900},"\u002Fdocs\u002Freading-the-form\u002Fthe-form","The form",": the full reactive surface that surrounds ",[13,904,5],{},[906,907,908],"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":910},[911,912,913,914,915,916,917],{"id":68,"depth":127,"text":69},{"id":154,"depth":127,"text":54},{"id":323,"depth":127,"text":324},{"id":537,"depth":127,"text":538},{"id":649,"depth":127,"text":225},{"id":788,"depth":127,"text":308},{"id":867,"depth":127,"text":868},"form.meta is the form-level FieldState aggregation plus seven form-only reads, submitting, submissionAttempts, departAttempts, submitError, errorCount, submitted, and instanceId.","md",{},[922,925,927,930],{"label":923,"value":924},"Category","Return property",{"label":176,"value":926,"kind":13},"FormMeta\u003CForm>",{"label":928,"value":929},"Reactive","Yes",{"label":931,"value":932},"Shape","FieldState aggregation + 7 form-only props",true,"\u002Fdocs\u002Freading-the-form\u002Fmeta",{"title":5,"description":918},null,"docs\u002Freading-the-form\u002Fmeta","MrJ1DJToQbYJO3o9bI-bMJT7SdWT5xceNdu-JZENMqI",1781745871906]