[{"data":1,"prerenderedAt":376},["ShallowReactive",2],{"content-\u002Fdocs\u002Fvalidation\u002Fwhen-validation-runs":3},{"id":4,"title":5,"body":6,"description":360,"extension":361,"meta":362,"metaRows":363,"navigation":370,"path":371,"seo":372,"source":373,"stem":374,"__hash__":375},"docs\u002Fdocs\u002Fvalidation\u002Fwhen-validation-runs.md","When validation runs",{"type":7,"value":8,"toc":354},"minimark",[9,13,33,36,43,104,109,167,189,197,202,212,216,223,263,269,283,287,297,323,327,350],[10,11,5],"h1",{"id":12},"when-validation-runs",[14,15,16],"blockquote",{},[17,18,19,20,24,25,28,29,32],"p",{},"Per-field validation triggers on ",[21,22,23],"code",{},"change",", ",[21,26,27],{},"blur",", or ",[21,30,31],{},"submit",": your call, per form. Sync refinements fire immediately; async refinements await.",[34,35],"docs-meta-table",{},[17,37,38,39,42],{},"Validation timing is configured per form via the ",[21,40,41],{},"validateOn"," option:",[44,45,50],"pre",{"className":46,"code":47,"language":48,"meta":49,"style":49},"language-ts shiki shiki-themes github-light github-dark","const form = useForm({\n  schema,\n  validateOn: 'change', \u002F\u002F default\n})\n","ts","",[21,51,52,76,82,98],{"__ignoreMap":49},[53,54,57,61,65,68,72],"span",{"class":55,"line":56},"line",1,[53,58,60],{"class":59},"szBVR","const",[53,62,64],{"class":63},"sj4cs"," form",[53,66,67],{"class":59}," =",[53,69,71],{"class":70},"sScJk"," useForm",[53,73,75],{"class":74},"sVt8B","({\n",[53,77,79],{"class":55,"line":78},2,[53,80,81],{"class":74},"  schema,\n",[53,83,85,88,92,94],{"class":55,"line":84},3,[53,86,87],{"class":74},"  validateOn: ",[53,89,91],{"class":90},"sZZnC","'change'",[53,93,24],{"class":74},[53,95,97],{"class":96},"sJ8bj","\u002F\u002F default\n",[53,99,101],{"class":55,"line":100},4,[53,102,103],{"class":74},"})\n",[105,106,108],"h2",{"id":107},"triggers","Triggers",[110,111,112,125],"table",{},[113,114,115],"thead",{},[116,117,118,122],"tr",{},[119,120,121],"th",{},"Value",[119,123,124],{},"Per-field validation fires on",[126,127,128,143,153],"tbody",{},[116,129,130,136],{},[131,132,133,135],"td",{},[21,134,91],{}," (default)",[131,137,138,139,142],{},"Every committed write to storage. Pairs with the directive's commit cadence (per-keystroke by default, per-blur on ",[21,140,141],{},".lazy",").",[116,144,145,150],{},[131,146,147],{},[21,148,149],{},"'blur'",[131,151,152],{},"When the input loses focus.",[116,154,155,160],{},[131,156,157],{},[21,158,159],{},"'submit'",[131,161,162,163,166],{},"Only when ",[21,164,165],{},"handleSubmit"," dispatches.",[17,168,169,170,173,174,177,178,181,182,184,185,188],{},"The directive's commit cadence and the validation trigger are independent. With default ",[21,171,172],{},"\u003Cinput v-register>"," and ",[21,175,176],{},"validateOn: 'change'",", both fire per keystroke. Switch to ",[21,179,180],{},"\u003Cinput v-register.lazy>"," and validation still rides the commit, which now lands on ",[21,183,23],{}," (per-blur). Switch to ",[21,186,187],{},"validateOn: 'blur'"," and validation skips the per-write rhythm entirely.",[17,190,191,192,196],{},"The same schema runs in every mode: the only thing that changes is ",[193,194,195],"em",{},"when"," a refinement gets evaluated.",[198,199],"docs-demo",{"label":200,"slug":201},"validateOn modes","validate-on-modes",[17,203,204,205,207,208,211],{},"Under ",[21,206,187],{},", leaving a field you never edited can't change any verdict, so Attaform skips the pass: it tracks whether the form has changed since the last validation and only revalidates when it has. Refocus a field that's showing an error, then tab away, and the error holds steady instead of blinking through ",[21,209,210],{},"'pending'"," and back.",[105,213,215],{"id":214},"debouncing","Debouncing",[17,217,218,219,222],{},"Pass a ",[21,220,221],{},"debounceMs"," to coalesce rapid bursts:",[44,224,226],{"className":46,"code":225,"language":48,"meta":49,"style":49},"useForm({\n  schema,\n  validateOn: 'change',\n  debounceMs: 200,\n})\n",[21,227,228,235,239,248,258],{"__ignoreMap":49},[53,229,230,233],{"class":55,"line":56},[53,231,232],{"class":70},"useForm",[53,234,75],{"class":74},[53,236,237],{"class":55,"line":78},[53,238,81],{"class":74},[53,240,241,243,245],{"class":55,"line":84},[53,242,87],{"class":74},[53,244,91],{"class":90},[53,246,247],{"class":74},",\n",[53,249,250,253,256],{"class":55,"line":100},[53,251,252],{"class":74},"  debounceMs: ",[53,254,255],{"class":63},"200",[53,257,247],{"class":74},[53,259,261],{"class":55,"line":260},5,[53,262,103],{"class":74},[17,264,265,266,268],{},"The field's last committed write wins after ",[21,267,221],{}," of quiet. Useful for expensive sync refinements; required for async refinements that hit a network (otherwise every keystroke fires a request).",[17,270,271,273,274,276,277,279,280,282],{},[21,272,221],{}," is only meaningful with ",[21,275,176],{},". TypeScript rejects pairing it with ",[21,278,149],{}," or ",[21,281,159],{},", so a misconfigured form is a compile error rather than a silent runtime drop.",[105,284,286],{"id":285},"sync-versus-async","Sync versus async",[17,288,289,290,24,293,296],{},"Sync refinements (",[21,291,292],{},"refine",[21,294,295],{},"superRefine"," with synchronous returns) run on the trigger. Async refinements (anything that returns a Promise) are awaited:",[298,299,300,311,317],"ul",{},[301,302,303,304,306,307,310],"li",{},"During typing (",[21,305,176],{},"), the field's ",[21,308,309],{},"form.fields.\u003Cpath>.validating"," flips true while the Promise is in flight.",[301,312,313,314,316],{},"On submit, ",[21,315,165],{}," waits for every active async refinement to settle before calling the success callback.",[301,318,319,322],{},[21,320,321],{},"form.meta.valid"," only flips true once every active path has resolved at least one validation pass, including the async ones. No flash-of-valid window.",[105,324,326],{"id":325},"where-to-next","Where to next",[298,328,329,341],{},[301,330,331,336,337,340],{},[332,333,335],"a",{"href":334},"\u002Fdocs\u002Fvalidation\u002Fshowing-errors","Display state and showing errors",": the ",[21,338,339],{},"getDisplayState"," predicate.",[301,342,343,349],{},[332,344,346],{"href":345},"\u002Fdocs\u002Freading-the-form\u002Ferrors",[21,347,348],{},"errors",": per-path error reads.",[351,352,353],"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 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);}",{"title":49,"searchDepth":78,"depth":78,"links":355},[356,357,358,359],{"id":107,"depth":78,"text":108},{"id":214,"depth":78,"text":215},{"id":285,"depth":78,"text":286},{"id":325,"depth":78,"text":326},"Attaform validates per field on change, blur, or submit, your call, per form. Sync refinements fire immediately; async refinements await.","md",{},[364,367,368],{"label":365,"value":366},"Category","Option",{"label":366,"value":41,"kind":21},{"label":369,"value":23,"kind":21},"Default",true,"\u002Fdocs\u002Fvalidation\u002Fwhen-validation-runs",{"title":5,"description":360},null,"docs\u002Fvalidation\u002Fwhen-validation-runs","1jpIyrmFBao93U9DyVBZF9_PKFTIuLb6AlzfJwN32VM",1780949760108]