[{"data":1,"prerenderedAt":1375},["ShallowReactive",2],{"content-\u002Fdocs\u002Frecipes\u002Ferror-display":3},{"id":4,"title":5,"body":6,"description":1368,"extension":1369,"meta":1370,"navigation":475,"path":1371,"seo":1372,"stem":1373,"__hash__":1374},"docs\u002Fdocs\u002Frecipes\u002Ferror-display.md","Error display",{"type":7,"value":8,"toc":1350},"minimark",[9,13,22,169,179,241,251,256,262,279,284,301,316,320,323,386,389,393,445,448,452,552,555,559,592,615,622,625,698,701,705,708,793,810,816,829,873,877,892,946,949,1064,1067,1093,1107,1110,1149,1157,1161,1241,1252,1276,1282,1291,1338,1346],[10,11,5],"h1",{"id":12},"error-display",[14,15,16,17,21],"p",{},"Validation errors live on ",[18,19,20],"code",{},"field.errors",", but rendering them takes\nmore than presence — most apps want errors to surface only after a\nsubmit attempt or after the user has actually interacted with a\nfield. Spelling that heuristic out at every error site bloats\ntemplates and drifts across components:",[23,24,29],"pre",{"className":25,"code":26,"language":27,"meta":28,"style":28},"language-vue shiki shiki-themes github-light github-dark","\u003C!-- Don't — the heuristic is repeated everywhere it renders -->\n\u003Cinput v-register=\"register('email')\" \u002F>\n\u003Cspan\n  v-if=\"\n    form.fields.email.errors.length > 0 &&\n    (form.meta.submitCount > 0 || (form.fields.email.touched && form.fields.email.dirty))\n  \"\n>\n  {{ form.fields.email.errors[0].message }}\n\u003C\u002Fspan>\n","vue","",[18,30,31,40,79,87,99,118,141,147,153,159],{"__ignoreMap":28},[32,33,36],"span",{"class":34,"line":35},"line",1,[32,37,39],{"class":38},"sJ8bj","\u003C!-- Don't — the heuristic is repeated everywhere it renders -->\n",[32,41,43,47,51,55,58,62,65,68,71,74,76],{"class":34,"line":42},2,[32,44,46],{"class":45},"sVt8B","\u003C",[32,48,50],{"class":49},"s9eBZ","input",[32,52,54],{"class":53},"sScJk"," v-register",[32,56,57],{"class":45},"=",[32,59,61],{"class":60},"sZZnC","\"",[32,63,64],{"class":53},"register",[32,66,67],{"class":45},"(",[32,69,70],{"class":60},"'email'",[32,72,73],{"class":45},")",[32,75,61],{"class":60},[32,77,78],{"class":45}," \u002F>\n",[32,80,82,84],{"class":34,"line":81},3,[32,83,46],{"class":45},[32,85,86],{"class":49},"span\n",[32,88,90,94,96],{"class":34,"line":89},4,[32,91,93],{"class":92},"szBVR","  v-if",[32,95,57],{"class":45},[32,97,98],{"class":60},"\"\n",[32,100,102,105,109,112,115],{"class":34,"line":101},5,[32,103,104],{"class":45},"    form.fields.email.errors.",[32,106,108],{"class":107},"sj4cs","length",[32,110,111],{"class":92}," >",[32,113,114],{"class":107}," 0",[32,116,117],{"class":92}," &&\n",[32,119,121,124,127,129,132,135,138],{"class":34,"line":120},6,[32,122,123],{"class":45},"    (form.meta.submitCount ",[32,125,126],{"class":92},">",[32,128,114],{"class":107},[32,130,131],{"class":92}," ||",[32,133,134],{"class":45}," (form.fields.email.touched ",[32,136,137],{"class":92},"&&",[32,139,140],{"class":45}," form.fields.email.dirty))\n",[32,142,144],{"class":34,"line":143},7,[32,145,146],{"class":60},"  \"\n",[32,148,150],{"class":34,"line":149},8,[32,151,152],{"class":45},">\n",[32,154,156],{"class":34,"line":155},9,[32,157,158],{"class":45},"  {{ form.fields.email.errors[0].message }}\n",[32,160,162,165,167],{"class":34,"line":161},10,[32,163,164],{"class":45},"\u003C\u002F",[32,166,32],{"class":49},[32,168,152],{"class":45},[14,170,171,174,175,178],{},[18,172,173],{},"field.showErrors"," and ",[18,176,177],{},"field.firstError"," collapse the whole pattern\nto a two-line idiom:",[23,180,182],{"className":25,"code":181,"language":27,"meta":28,"style":28},"\u003Cinput v-register=\"register('email')\" \u002F>\n\u003Cspan v-if=\"form.fields.email.showErrors\">\n  {{ form.fields.email.firstError?.message }}\n\u003C\u002Fspan>\n",[18,183,184,208,228,233],{"__ignoreMap":28},[32,185,186,188,190,192,194,196,198,200,202,204,206],{"class":34,"line":35},[32,187,46],{"class":45},[32,189,50],{"class":49},[32,191,54],{"class":53},[32,193,57],{"class":45},[32,195,61],{"class":60},[32,197,64],{"class":53},[32,199,67],{"class":45},[32,201,70],{"class":60},[32,203,73],{"class":45},[32,205,61],{"class":60},[32,207,78],{"class":45},[32,209,210,212,214,217,219,221,224,226],{"class":34,"line":42},[32,211,46],{"class":45},[32,213,32],{"class":49},[32,215,216],{"class":92}," v-if",[32,218,57],{"class":45},[32,220,61],{"class":60},[32,222,223],{"class":45},"form.fields.email.showErrors",[32,225,61],{"class":60},[32,227,152],{"class":45},[32,229,230],{"class":34,"line":81},[32,231,232],{"class":45},"  {{ form.fields.email.firstError?.message }}\n",[32,234,235,237,239],{"class":34,"line":89},[32,236,164],{"class":45},[32,238,32],{"class":49},[32,240,152],{"class":45},[14,242,243,246,247,250],{},[18,244,245],{},"showErrors"," is the gate, ",[18,248,249],{},"firstError"," is the data. Each is reactive,\neach is independent, each works on leaf and container paths alike.",[252,253,255],"h2",{"id":254},"the-two-primitives","The two primitives",[257,258,260],"h3",{"id":259},"fieldshowerrors",[18,261,173],{},[14,263,264,267,268,271,272,274,275,278],{},[18,265,266],{},"true"," when there are errors at this path AND the configured\nheuristic decides they're ready to render. The framework gates the\npredicate on ",[18,269,270],{},"errors.length > 0",", so ",[18,273,245],{}," is ",[18,276,277],{},"false","\nwhenever there's nothing to show — regardless of the heuristic.",[257,280,282],{"id":281},"fieldfirsterror",[18,283,177],{},[14,285,286,287,290,291,294,295,297,298,300],{},"The first ",[18,288,289],{},"ValidationError"," at this path in deterministic\nschema-declaration order, or ",[18,292,293],{},"undefined"," when there are none. Pure\ndata — independent of ",[18,296,245],{},". Reach for it when you want a\nsingle highest-priority message; reach for ",[18,299,20],{}," when you\nwant the full list.",[14,302,303,274,305,308,309,312,313,315],{},[18,304,249],{},[18,306,307],{},"errors[0]"," — the underlying ordering is stable\n(schema → blank → user errors at one path; bucketed by\n",[18,310,311],{},"pathOrdinal"," across descendants for container paths) so the same\nset of errors always produces the same ",[18,314,249],{},".",[252,317,319],{"id":318},"the-default-heuristic","The default heuristic",[14,321,322],{},"Out of the box:",[23,324,328],{"className":325,"code":326,"language":327,"meta":28,"style":28},"language-ts shiki shiki-themes github-light github-dark","const defaultShouldShowErrors = (field, formMeta) =>\n  formMeta.submitCount > 0 || (field.touched === true && field.dirty)\n","ts",[18,329,330,360],{"__ignoreMap":28},[32,331,332,335,338,341,344,348,351,354,357],{"class":34,"line":35},[32,333,334],{"class":92},"const",[32,336,337],{"class":53}," defaultShouldShowErrors",[32,339,340],{"class":92}," =",[32,342,343],{"class":45}," (",[32,345,347],{"class":346},"s4XuR","field",[32,349,350],{"class":45},", ",[32,352,353],{"class":346},"formMeta",[32,355,356],{"class":45},") ",[32,358,359],{"class":92},"=>\n",[32,361,362,365,367,369,371,374,377,380,383],{"class":34,"line":42},[32,363,364],{"class":45},"  formMeta.submitCount ",[32,366,126],{"class":92},[32,368,114],{"class":107},[32,370,131],{"class":92},[32,372,373],{"class":45}," (field.touched ",[32,375,376],{"class":92},"===",[32,378,379],{"class":107}," true",[32,381,382],{"class":92}," &&",[32,384,385],{"class":45}," field.dirty)\n",[14,387,388],{},"\"Show errors after the first submit attempt OR after the user has\ninteracted with the field AND made a change.\" Standard form UX —\nerrors stay quiet until they're actionable.",[252,390,392],{"id":391},"override-per-form","Override per form",[23,394,396],{"className":325,"code":395,"language":327,"meta":28,"style":28},"useForm({\n  schema,\n  shouldShowErrors: (field, formMeta) => formMeta.submitCount > 0,\n})\n",[18,397,398,406,411,440],{"__ignoreMap":28},[32,399,400,403],{"class":34,"line":35},[32,401,402],{"class":53},"useForm",[32,404,405],{"class":45},"({\n",[32,407,408],{"class":34,"line":42},[32,409,410],{"class":45},"  schema,\n",[32,412,413,416,419,421,423,425,427,430,433,435,437],{"class":34,"line":81},[32,414,415],{"class":53},"  shouldShowErrors",[32,417,418],{"class":45},": (",[32,420,347],{"class":346},[32,422,350],{"class":45},[32,424,353],{"class":346},[32,426,356],{"class":45},[32,428,429],{"class":92},"=>",[32,431,432],{"class":45}," formMeta.submitCount ",[32,434,126],{"class":92},[32,436,114],{"class":107},[32,438,439],{"class":45},",\n",[32,441,442],{"class":34,"line":89},[32,443,444],{"class":45},"})\n",[14,446,447],{},"Per-form override beats the plugin default and beats the library\ndefault.",[252,449,451],{"id":450},"override-app-wide","Override app-wide",[23,453,455],{"className":325,"code":454,"language":327,"meta":28,"style":28},"import { createAttaform } from 'attaform'\n\ncreateApp(App).use(\n  createAttaform({\n    defaults: {\n      shouldShowErrors: (field, formMeta) => formMeta.submitCount > 0 || field.touched === true,\n    },\n  })\n)\n",[18,456,457,471,477,491,498,503,537,542,547],{"__ignoreMap":28},[32,458,459,462,465,468],{"class":34,"line":35},[32,460,461],{"class":92},"import",[32,463,464],{"class":45}," { createAttaform } ",[32,466,467],{"class":92},"from",[32,469,470],{"class":60}," 'attaform'\n",[32,472,473],{"class":34,"line":42},[32,474,476],{"emptyLinePlaceholder":475},true,"\n",[32,478,479,482,485,488],{"class":34,"line":81},[32,480,481],{"class":53},"createApp",[32,483,484],{"class":45},"(App).",[32,486,487],{"class":53},"use",[32,489,490],{"class":45},"(\n",[32,492,493,496],{"class":34,"line":89},[32,494,495],{"class":53},"  createAttaform",[32,497,405],{"class":45},[32,499,500],{"class":34,"line":101},[32,501,502],{"class":45},"    defaults: {\n",[32,504,505,508,510,512,514,516,518,520,522,524,526,528,531,533,535],{"class":34,"line":120},[32,506,507],{"class":53},"      shouldShowErrors",[32,509,418],{"class":45},[32,511,347],{"class":346},[32,513,350],{"class":45},[32,515,353],{"class":346},[32,517,356],{"class":45},[32,519,429],{"class":92},[32,521,432],{"class":45},[32,523,126],{"class":92},[32,525,114],{"class":107},[32,527,131],{"class":92},[32,529,530],{"class":45}," field.touched ",[32,532,376],{"class":92},[32,534,379],{"class":107},[32,536,439],{"class":45},[32,538,539],{"class":34,"line":143},[32,540,541],{"class":45},"    },\n",[32,543,544],{"class":34,"line":149},[32,545,546],{"class":45},"  })\n",[32,548,549],{"class":34,"line":155},[32,550,551],{"class":45},")\n",[14,553,554],{},"Every form in the app inherits this heuristic unless it sets its\nown.",[252,556,558],{"id":557},"boolean-shorthand","Boolean shorthand",[23,560,562],{"className":325,"code":561,"language":327,"meta":28,"style":28},"useForm({ schema, shouldShowErrors: true }) \u002F\u002F always show when errors exist\nuseForm({ schema, shouldShowErrors: false }) \u002F\u002F never show — adopters who gate manually\n",[18,563,564,579],{"__ignoreMap":28},[32,565,566,568,571,573,576],{"class":34,"line":35},[32,567,402],{"class":53},[32,569,570],{"class":45},"({ schema, shouldShowErrors: ",[32,572,266],{"class":107},[32,574,575],{"class":45}," }) ",[32,577,578],{"class":38},"\u002F\u002F always show when errors exist\n",[32,580,581,583,585,587,589],{"class":34,"line":42},[32,582,402],{"class":53},[32,584,570],{"class":45},[32,586,277],{"class":107},[32,588,575],{"class":45},[32,590,591],{"class":38},"\u002F\u002F never show — adopters who gate manually\n",[14,593,594,596,597,599,600,602,603,605,606,609,610,612,613,315],{},[18,595,266],{}," means \"show errors whenever any exist\"; ",[18,598,277],{}," means \"never\ngate via ",[18,601,245],{}," — read ",[18,604,249],{}," \u002F ",[18,607,608],{},"errors"," directly and\nwrite your own template logic.\" ",[18,611,266],{}," does NOT render an empty\nerrors block — the framework still gates on ",[18,614,270],{},[252,616,618,619],{"id":617},"compose-with-defaultshouldshowerrors","Compose with ",[18,620,621],{},"defaultShouldShowErrors",[14,623,624],{},"The library default is publicly exported. Layered predicates that\nadd a special case but otherwise defer to the library default pick\nup future heuristic refinements automatically:",[23,626,628],{"className":325,"code":627,"language":327,"meta":28,"style":28},"import { defaultShouldShowErrors } from 'attaform'\n\nuseForm({\n  schema,\n  shouldShowErrors: (field, formMeta) =>\n    field.path[0] === 'urgent' || defaultShouldShowErrors(field, formMeta),\n})\n",[18,629,630,641,645,651,655,671,694],{"__ignoreMap":28},[32,631,632,634,637,639],{"class":34,"line":35},[32,633,461],{"class":92},[32,635,636],{"class":45}," { defaultShouldShowErrors } ",[32,638,467],{"class":92},[32,640,470],{"class":60},[32,642,643],{"class":34,"line":42},[32,644,476],{"emptyLinePlaceholder":475},[32,646,647,649],{"class":34,"line":81},[32,648,402],{"class":53},[32,650,405],{"class":45},[32,652,653],{"class":34,"line":89},[32,654,410],{"class":45},[32,656,657,659,661,663,665,667,669],{"class":34,"line":101},[32,658,415],{"class":53},[32,660,418],{"class":45},[32,662,347],{"class":346},[32,664,350],{"class":45},[32,666,353],{"class":346},[32,668,356],{"class":45},[32,670,359],{"class":92},[32,672,673,676,679,682,684,687,689,691],{"class":34,"line":120},[32,674,675],{"class":45},"    field.path[",[32,677,678],{"class":107},"0",[32,680,681],{"class":45},"] ",[32,683,376],{"class":92},[32,685,686],{"class":60}," 'urgent'",[32,688,131],{"class":92},[32,690,337],{"class":53},[32,692,693],{"class":45},"(field, formMeta),\n",[32,695,696],{"class":34,"line":143},[32,697,444],{"class":45},[14,699,700],{},"If a future Attaform release tweaks the default heuristic (say, to\nalso fire on blur), every layered predicate that defers to the\ndefault inherits the change without code edits.",[252,702,704],{"id":703},"container-paths","Container paths",[14,706,707],{},"Both primitives work on container paths — render row-level or\nsection-level summary errors with the same idiom:",[23,709,711],{"className":25,"code":710,"language":27,"meta":28,"style":28},"\u003Cdiv v-for=\"(_, i) in form.values.users\" :key=\"i\">\n  \u003Cinput v-register=\"register(['users', i, 'name'])\" \u002F>\n  \u003Cinput v-register=\"register(['users', i, 'email'])\" \u002F>\n  \u003C!-- One row-level summary instead of per-field repetition -->\n  \u003Cspan v-if=\"form.fields.users[i]?.showErrors\" class=\"row-error\">\n    {{ form.fields.users[i]?.firstError?.message }}\n  \u003C\u002Fspan>\n\u003C\u002Fdiv>\n",[18,712,713,755,760,765,770,775,780,785],{"__ignoreMap":28},[32,714,715,717,720,723,725,727,730,733,736,738,741,744,746,748,751,753],{"class":34,"line":35},[32,716,46],{"class":45},[32,718,719],{"class":49},"div",[32,721,722],{"class":92}," v-for",[32,724,57],{"class":45},[32,726,61],{"class":60},[32,728,729],{"class":45},"(_, i) ",[32,731,732],{"class":92},"in",[32,734,735],{"class":45}," form.values.users",[32,737,61],{"class":60},[32,739,740],{"class":45}," :",[32,742,743],{"class":53},"key",[32,745,57],{"class":45},[32,747,61],{"class":60},[32,749,750],{"class":45},"i",[32,752,61],{"class":60},[32,754,152],{"class":45},[32,756,757],{"class":34,"line":42},[32,758,759],{"class":45},"  \u003Cinput v-register=\"register(['users', i, 'name'])\" \u002F>\n",[32,761,762],{"class":34,"line":81},[32,763,764],{"class":45},"  \u003Cinput v-register=\"register(['users', i, 'email'])\" \u002F>\n",[32,766,767],{"class":34,"line":89},[32,768,769],{"class":45},"  \u003C!-- One row-level summary instead of per-field repetition -->\n",[32,771,772],{"class":34,"line":101},[32,773,774],{"class":45},"  \u003Cspan v-if=\"form.fields.users[i]?.showErrors\" class=\"row-error\">\n",[32,776,777],{"class":34,"line":120},[32,778,779],{"class":45},"    {{ form.fields.users[i]?.firstError?.message }}\n",[32,781,782],{"class":34,"line":143},[32,783,784],{"class":45},"  \u003C\u002Fspan>\n",[32,786,787,789,791],{"class":34,"line":149},[32,788,164],{"class":45},[32,790,719],{"class":49},[32,792,152],{"class":45},[14,794,795,796,798,799,801,802,805,806,809],{},"For a container, ",[18,797,249],{}," is the first error in the aggregated\nsubtree (descendants sorted by schema-declaration order); ",[18,800,245],{},"\nruns the predicate against the container's aggregated state\n(",[18,803,804],{},"touched"," becomes \"any descendant touched\", ",[18,807,808],{},"dirty"," becomes \"any\ndescendant dirty\", etc.). Same predicate; uniform across depth.",[252,811,813],{"id":812},"formmetashowerrors",[18,814,815],{},"form.meta.showErrors",[14,817,818,821,822,824,825,828],{},[18,819,820],{},"form.meta"," is the root container's FieldState plus the form-level\nlifecycle fields, so ",[18,823,815],{}," and\n",[18,826,827],{},"form.meta.firstError"," are the form-wide rollup:",[23,830,832],{"className":25,"code":831,"language":27,"meta":28,"style":28},"\u003Cdiv v-if=\"form.meta.showErrors\" class=\"form-summary\">\n  Please fix the {{ form.meta.errors.length }} highlighted issue(s).\n\u003C\u002Fdiv>\n",[18,833,834,860,865],{"__ignoreMap":28},[32,835,836,838,840,842,844,846,848,850,853,855,858],{"class":34,"line":35},[32,837,46],{"class":45},[32,839,719],{"class":49},[32,841,216],{"class":92},[32,843,57],{"class":45},[32,845,61],{"class":60},[32,847,815],{"class":45},[32,849,61],{"class":60},[32,851,852],{"class":53}," class",[32,854,57],{"class":45},[32,856,857],{"class":60},"\"form-summary\"",[32,859,152],{"class":45},[32,861,862],{"class":34,"line":42},[32,863,864],{"class":45},"  Please fix the {{ form.meta.errors.length }} highlighted issue(s).\n",[32,866,867,869,871],{"class":34,"line":81},[32,868,164],{"class":45},[32,870,719],{"class":49},[32,872,152],{"class":45},[252,874,876],{"id":875},"form-level-errors","Form-level errors",[14,878,879,880,883,884,887,888,891],{},"Messages that aren't tied to a single field — \"capacity exceeded\",\n\"this combination already exists\", server-side failures from a\nsubmit handler — live in a dedicated bucket at the empty-string\npath ",[18,881,882],{},"['']",". Write them with ",[18,885,886],{},"form.setFormErrors",", clear them with\n",[18,889,890],{},"form.clearFormErrors",":",[23,893,895],{"className":325,"code":894,"language":327,"meta":28,"style":28},"form.setFormErrors([{ message: 'Capacity exceeded' }])\nform.setFormErrors([{ message: 'Network unreachable', code: 'api:network' }])\nform.clearFormErrors() \u002F\u002F or setFormErrors([])\n",[18,896,897,914,933],{"__ignoreMap":28},[32,898,899,902,905,908,911],{"class":34,"line":35},[32,900,901],{"class":45},"form.",[32,903,904],{"class":53},"setFormErrors",[32,906,907],{"class":45},"([{ message: ",[32,909,910],{"class":60},"'Capacity exceeded'",[32,912,913],{"class":45}," }])\n",[32,915,916,918,920,922,925,928,931],{"class":34,"line":42},[32,917,901],{"class":45},[32,919,904],{"class":53},[32,921,907],{"class":45},[32,923,924],{"class":60},"'Network unreachable'",[32,926,927],{"class":45},", code: ",[32,929,930],{"class":60},"'api:network'",[32,932,913],{"class":45},[32,934,935,937,940,943],{"class":34,"line":81},[32,936,901],{"class":45},[32,938,939],{"class":53},"clearFormErrors",[32,941,942],{"class":45},"() ",[32,944,945],{"class":38},"\u002F\u002F or setFormErrors([])\n",[14,947,948],{},"Render them above (or below) the form by reading the empty-path\nbucket directly:",[23,950,952],{"className":25,"code":951,"language":27,"meta":28,"style":28},"\u003Ctemplate>\n  \u003Cdiv v-if=\"form.errors('')\" role=\"alert\" class=\"form-banner\">\n    \u003Cp v-for=\"e in form.errors('')\" :key=\"e.message\">{{ e.message }}\u003C\u002Fp>\n  \u003C\u002Fdiv>\n\n  \u003Cinput v-register=\"form.register('email')\" \u002F>\n  \u003C!-- field errors as usual -->\n\u003C\u002Ftemplate>\n",[18,953,954,963,994,1023,1032,1036,1051,1056],{"__ignoreMap":28},[32,955,956,958,961],{"class":34,"line":35},[32,957,46],{"class":45},[32,959,960],{"class":49},"template",[32,962,152],{"class":45},[32,964,965,968,970,972,974,977,980,982,985,987,989,992],{"class":34,"line":42},[32,966,967],{"class":45},"  \u003C",[32,969,719],{"class":49},[32,971,216],{"class":53},[32,973,57],{"class":45},[32,975,976],{"class":60},"\"form.errors('')\"",[32,978,979],{"class":53}," role",[32,981,57],{"class":45},[32,983,984],{"class":60},"\"alert\"",[32,986,852],{"class":53},[32,988,57],{"class":45},[32,990,991],{"class":60},"\"form-banner\"",[32,993,152],{"class":45},[32,995,996,999,1001,1003,1005,1008,1011,1013,1016,1019,1021],{"class":34,"line":81},[32,997,998],{"class":45},"    \u003C",[32,1000,14],{"class":49},[32,1002,722],{"class":53},[32,1004,57],{"class":45},[32,1006,1007],{"class":60},"\"e in form.errors('')\"",[32,1009,1010],{"class":53}," :key",[32,1012,57],{"class":45},[32,1014,1015],{"class":60},"\"e.message\"",[32,1017,1018],{"class":45},">{{ e.message }}\u003C\u002F",[32,1020,14],{"class":49},[32,1022,152],{"class":45},[32,1024,1025,1028,1030],{"class":34,"line":89},[32,1026,1027],{"class":45},"  \u003C\u002F",[32,1029,719],{"class":49},[32,1031,152],{"class":45},[32,1033,1034],{"class":34,"line":101},[32,1035,476],{"emptyLinePlaceholder":475},[32,1037,1038,1040,1042,1044,1046,1049],{"class":34,"line":120},[32,1039,967],{"class":45},[32,1041,50],{"class":49},[32,1043,54],{"class":53},[32,1045,57],{"class":45},[32,1047,1048],{"class":60},"\"form.register('email')\"",[32,1050,78],{"class":45},[32,1052,1053],{"class":34,"line":143},[32,1054,1055],{"class":38},"  \u003C!-- field errors as usual -->\n",[32,1057,1058,1060,1062],{"class":34,"line":149},[32,1059,164],{"class":45},[32,1061,960],{"class":49},[32,1063,152],{"class":45},[14,1065,1066],{},"Three read paths surface the bucket:",[1068,1069,1070,1081,1087],"ul",{},[1071,1072,1073,1076,1077,1080],"li",{},[18,1074,1075],{},"form.errors('')"," — call-form with the empty-string path, returns\n",[18,1078,1079],{},"ValidationError[] | undefined",". Use this in templates and script.",[1071,1082,1083,1086],{},[18,1084,1085],{},"form.errors['']"," — bracket access on the drill proxy.",[1071,1088,1089,1092],{},[18,1090,1091],{},"form.meta.errors"," — the flat aggregate (all errors at every\ndepth, form-level included).",[14,1094,1095,1098,1099,1102,1103,1106],{},[18,1096,1097],{},"form.errors.\u003Cfield>"," dot-access skips the bucket because there's no\n",[18,1100,1101],{},"''"," property in JS dot-notation. That's the only surface where the\nbucket is invisible; iteration \u002F ",[18,1104,1105],{},"JSON.stringify(form.errors)"," \u002F\ntemplate interpolation all show it at the empty-string key.",[14,1108,1109],{},"Form-level entries:",[1068,1111,1112,1122,1134,1140],{},[1071,1113,1114,1121],{},[1115,1116,1117,1118],"strong",{},"Survive ",[18,1119,1120],{},"setFieldErrors"," — the two surfaces own logically\ndistinct slots, so writing field errors doesn't wipe the form\nbanner and vice versa.",[1071,1123,1124,1129,1130,1133],{},[1115,1125,1117,1126],{},[18,1127,1128],{},"clearFieldErrors()"," — the no-path \"clear all field\nerrors\" call leaves the form-level bucket alone. Pass\n",[18,1131,1132],{},"clearFormErrors()"," to drop them explicitly.",[1071,1135,1136,1139],{},[1115,1137,1138],{},"Are NOT cleared on schema revalidation"," — they're user-owned\ndata; the consumer manages their lifetime.",[1071,1141,1142,1148],{},[1115,1143,1144,1145],{},"ARE cleared by ",[18,1146,1147],{},"reset()"," — reset returns the form to its\ninitial state, which has no errors.",[14,1150,1151,1152,315],{},"For surfacing server-returned failures from a submit handler, see\n",[1153,1154,1156],"a",{"href":1155},"\u002Fdocs\u002Frecipes\u002Fserver-errors#non-field-errors","server errors > non-field errors",[252,1158,1160],{"id":1159},"predicate-signature","Predicate signature",[23,1162,1164],{"className":325,"code":1163,"language":327,"meta":28,"style":28},"type ShouldShowErrors = (\n  field: Omit\u003CFieldState, 'showErrors' | 'firstError'>,\n  formMeta: Omit\u003CFormMeta, 'showErrors' | 'firstError'>\n) => boolean\n",[18,1165,1166,1179,1208,1232],{"__ignoreMap":28},[32,1167,1168,1171,1174,1176],{"class":34,"line":35},[32,1169,1170],{"class":92},"type",[32,1172,1173],{"class":53}," ShouldShowErrors",[32,1175,340],{"class":92},[32,1177,1178],{"class":45}," (\n",[32,1180,1181,1184,1186,1189,1191,1194,1196,1199,1202,1205],{"class":34,"line":42},[32,1182,1183],{"class":346},"  field",[32,1185,891],{"class":92},[32,1187,1188],{"class":53}," Omit",[32,1190,46],{"class":45},[32,1192,1193],{"class":53},"FieldState",[32,1195,350],{"class":45},[32,1197,1198],{"class":60},"'showErrors'",[32,1200,1201],{"class":92}," |",[32,1203,1204],{"class":60}," 'firstError'",[32,1206,1207],{"class":45},">,\n",[32,1209,1210,1213,1215,1217,1219,1222,1224,1226,1228,1230],{"class":34,"line":81},[32,1211,1212],{"class":346},"  formMeta",[32,1214,891],{"class":92},[32,1216,1188],{"class":53},[32,1218,46],{"class":45},[32,1220,1221],{"class":53},"FormMeta",[32,1223,350],{"class":45},[32,1225,1198],{"class":60},[32,1227,1201],{"class":92},[32,1229,1204],{"class":60},[32,1231,152],{"class":45},[32,1233,1234,1236,1238],{"class":34,"line":89},[32,1235,356],{"class":45},[32,1237,429],{"class":92},[32,1239,1240],{"class":107}," boolean\n",[14,1242,1243,1244,605,1246,1248,1249,315],{},"Both arguments omit ",[18,1245,245],{},[18,1247,249],{}," — those are derived\nFROM this predicate, so reading them inside would be a self-\nreference. The omit is enforced at the type level AND at runtime\n(the keys literally are not present on the objects), so cycles are\nimpossible whether you're writing TypeScript, vanilla JS, or\ncasting through ",[18,1250,1251],{},"as",[14,1253,1254,1255,174,1258,1261,1262,439,1265,1268,1269,350,1272,1275],{},"The predicate must be ",[1115,1256,1257],{},"pure",[1115,1259,1260],{},"SSR-safe",". It runs inside Vue\ncomputeds; reading reactive state (",[18,1263,1264],{},"field.touched",[18,1266,1267],{},"formMeta.submitCount",", etc.) registers as a dependency\nautomatically, but DOM access (",[18,1270,1271],{},"window",[18,1273,1274],{},"document",") breaks SSR.",[252,1277,1279,1280],{"id":1278},"opting-out-of-showerrors","Opting out of ",[18,1281,245],{},[14,1283,1284,1285,1287,1288,1290],{},"Adopters who want full control read ",[18,1286,20],{}," (or\n",[18,1289,177],{}," for the sugar) and gate rendering with their own\ntemplate logic:",[23,1292,1294],{"className":25,"code":1293,"language":27,"meta":28,"style":28},"\u003Cspan v-if=\"form.fields.email.errors.length > 0 && customGate\">\n  {{ form.fields.email.firstError?.message }}\n\u003C\u002Fspan>\n",[18,1295,1296,1326,1330],{"__ignoreMap":28},[32,1297,1298,1300,1302,1304,1306,1308,1311,1313,1315,1317,1319,1322,1324],{"class":34,"line":35},[32,1299,46],{"class":45},[32,1301,32],{"class":49},[32,1303,216],{"class":92},[32,1305,57],{"class":45},[32,1307,61],{"class":60},[32,1309,1310],{"class":45},"form.fields.email.errors.",[32,1312,108],{"class":107},[32,1314,111],{"class":92},[32,1316,114],{"class":107},[32,1318,382],{"class":92},[32,1320,1321],{"class":45}," customGate",[32,1323,61],{"class":60},[32,1325,152],{"class":45},[32,1327,1328],{"class":34,"line":42},[32,1329,232],{"class":45},[32,1331,1332,1334,1336],{"class":34,"line":81},[32,1333,164],{"class":45},[32,1335,32],{"class":49},[32,1337,152],{"class":45},[14,1339,1340,1342,1343,1345],{},[18,1341,249],{}," is always available; ",[18,1344,245],{}," is the convenience.",[1347,1348,1349],"style",{},"html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}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 .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 .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}",{"title":28,"searchDepth":42,"depth":42,"links":1351},[1352,1356,1357,1358,1359,1360,1362,1363,1364,1365,1366],{"id":254,"depth":42,"text":255,"children":1353},[1354,1355],{"id":259,"depth":81,"text":173},{"id":281,"depth":81,"text":177},{"id":318,"depth":42,"text":319},{"id":391,"depth":42,"text":392},{"id":450,"depth":42,"text":451},{"id":557,"depth":42,"text":558},{"id":617,"depth":42,"text":1361},"Compose with defaultShouldShowErrors",{"id":703,"depth":42,"text":704},{"id":812,"depth":42,"text":815},{"id":875,"depth":42,"text":876},{"id":1159,"depth":42,"text":1160},{"id":1278,"depth":42,"text":1367},"Opting out of showErrors","Centralise the \"should I render this error?\" heuristic with `field.showErrors` and `field.firstError`. Override per-form, app-wide, or compose with the library default for a layered predicate.","md",{},"\u002Fdocs\u002Frecipes\u002Ferror-display",{"title":5,"description":1368},"docs\u002Frecipes\u002Ferror-display","sCU5f3i-XWSaT8AhuVx3gDPNoxsjiw6Mfmzk2SBh5co",1778695669335]