[{"data":1,"prerenderedAt":1283},["ShallowReactive",2],{"content-\u002Fdocs\u002Frecipes\u002Fasync-validation":3},{"id":4,"title":5,"body":6,"description":1276,"extension":1277,"meta":1278,"navigation":74,"path":1279,"seo":1280,"stem":1281,"__hash__":1282},"docs\u002Fdocs\u002Frecipes\u002Fasync-validation.md","Async validation",{"type":7,"value":8,"toc":1264},"minimark",[9,13,22,27,306,315,322,331,523,533,540,546,638,652,656,671,712,716,746,914,923,927,934,1042,1045,1049,1052,1150,1153,1157,1166,1243,1260],[10,11,5],"h1",{"id":12},"async-validation",[14,15,16,17,21],"p",{},"Use ",[18,19,20],"code",{},"z.refine(async …)"," anywhere in your schema — uniqueness checks,\nallow-lists, server availability. Attaform awaits the result before\ndispatching your submit handler.",[23,24,26],"h2",{"id":25},"async-refinements","Async refinements",[28,29,34],"pre",{"className":30,"code":31,"language":32,"meta":33,"style":33},"language-ts shiki shiki-themes github-light github-dark","import { z } from 'zod'\nimport { useForm } from 'attaform\u002Fzod'\n\nconst signupSchema = z.object({\n  email: z.email().refine(async (value) => {\n    const res = await fetch(`\u002Fapi\u002Femail-available?e=${encodeURIComponent(value)}`)\n    const { available } = (await res.json()) as { available: boolean }\n    return available\n  }, 'Email already registered'),\n  password: z.string().min(8),\n})\n\nconst { handleSubmit, errors } = useForm({ schema: signupSchema, key: 'signup' })\n","ts","",[18,35,36,56,69,76,99,136,174,221,230,242,263,269,274],{"__ignoreMap":33},[37,38,41,45,49,52],"span",{"class":39,"line":40},"line",1,[37,42,44],{"class":43},"szBVR","import",[37,46,48],{"class":47},"sVt8B"," { z } ",[37,50,51],{"class":43},"from",[37,53,55],{"class":54},"sZZnC"," 'zod'\n",[37,57,59,61,64,66],{"class":39,"line":58},2,[37,60,44],{"class":43},[37,62,63],{"class":47}," { useForm } ",[37,65,51],{"class":43},[37,67,68],{"class":54}," 'attaform\u002Fzod'\n",[37,70,72],{"class":39,"line":71},3,[37,73,75],{"emptyLinePlaceholder":74},true,"\n",[37,77,79,82,86,89,92,96],{"class":39,"line":78},4,[37,80,81],{"class":43},"const",[37,83,85],{"class":84},"sj4cs"," signupSchema",[37,87,88],{"class":43}," =",[37,90,91],{"class":47}," z.",[37,93,95],{"class":94},"sScJk","object",[37,97,98],{"class":47},"({\n",[37,100,102,105,108,111,114,117,120,123,127,130,133],{"class":39,"line":101},5,[37,103,104],{"class":47},"  email: z.",[37,106,107],{"class":94},"email",[37,109,110],{"class":47},"().",[37,112,113],{"class":94},"refine",[37,115,116],{"class":47},"(",[37,118,119],{"class":43},"async",[37,121,122],{"class":47}," (",[37,124,126],{"class":125},"s4XuR","value",[37,128,129],{"class":47},") ",[37,131,132],{"class":43},"=>",[37,134,135],{"class":47}," {\n",[37,137,139,142,145,147,150,153,155,158,161,163,165,168,171],{"class":39,"line":138},6,[37,140,141],{"class":43},"    const",[37,143,144],{"class":84}," res",[37,146,88],{"class":43},[37,148,149],{"class":43}," await",[37,151,152],{"class":94}," fetch",[37,154,116],{"class":47},[37,156,157],{"class":54},"`\u002Fapi\u002Femail-available?e=${",[37,159,160],{"class":94},"encodeURIComponent",[37,162,116],{"class":54},[37,164,126],{"class":47},[37,166,167],{"class":54},")",[37,169,170],{"class":54},"}`",[37,172,173],{"class":47},")\n",[37,175,177,179,182,185,188,191,193,196,199,202,205,208,210,212,215,218],{"class":39,"line":176},7,[37,178,141],{"class":43},[37,180,181],{"class":47}," { ",[37,183,184],{"class":84},"available",[37,186,187],{"class":47}," } ",[37,189,190],{"class":43},"=",[37,192,122],{"class":47},[37,194,195],{"class":43},"await",[37,197,198],{"class":47}," res.",[37,200,201],{"class":94},"json",[37,203,204],{"class":47},"()) ",[37,206,207],{"class":43},"as",[37,209,181],{"class":47},[37,211,184],{"class":125},[37,213,214],{"class":43},":",[37,216,217],{"class":84}," boolean",[37,219,220],{"class":47}," }\n",[37,222,224,227],{"class":39,"line":223},8,[37,225,226],{"class":43},"    return",[37,228,229],{"class":47}," available\n",[37,231,233,236,239],{"class":39,"line":232},9,[37,234,235],{"class":47},"  }, ",[37,237,238],{"class":54},"'Email already registered'",[37,240,241],{"class":47},"),\n",[37,243,245,248,251,253,256,258,261],{"class":39,"line":244},10,[37,246,247],{"class":47},"  password: z.",[37,249,250],{"class":94},"string",[37,252,110],{"class":47},[37,254,255],{"class":94},"min",[37,257,116],{"class":47},[37,259,260],{"class":84},"8",[37,262,241],{"class":47},[37,264,266],{"class":39,"line":265},11,[37,267,268],{"class":47},"})\n",[37,270,272],{"class":39,"line":271},12,[37,273,75],{"emptyLinePlaceholder":74},[37,275,277,279,281,284,287,290,292,294,297,300,303],{"class":39,"line":276},13,[37,278,81],{"class":43},[37,280,181],{"class":47},[37,282,283],{"class":84},"handleSubmit",[37,285,286],{"class":47},", ",[37,288,289],{"class":84},"errors",[37,291,187],{"class":47},[37,293,190],{"class":43},[37,295,296],{"class":94}," useForm",[37,298,299],{"class":47},"({ schema: signupSchema, key: ",[37,301,302],{"class":54},"'signup'",[37,304,305],{"class":47}," })\n",[14,307,308,309,311,312,314],{},"That's all the wiring you need. ",[18,310,283],{}," validates, waits for\nany async refinement to settle, and then dispatches to your callback\n(or populates ",[18,313,289],{}," if validation fails).",[23,316,318,319],{"id":317},"live-checking-ui-with-validate","Live \"checking…\" UI with ",[18,320,321],{},"validate()",[14,323,324,326,327,330],{},[18,325,321],{}," returns a reactive ref whose value carries a ",[18,328,329],{},"pending","\nflag — use it to show a spinner while async validation is in flight.",[28,332,336],{"className":333,"code":334,"language":335,"meta":33,"style":33},"language-vue shiki shiki-themes github-light github-dark","\u003Cscript setup lang=\"ts\">\n  const { validate } = useForm({ schema: signupSchema, key: 'signup' })\n  const status = validate()\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003Cp v-if=\"status.pending\">Checking…\u003C\u002Fp>\n  \u003Cp v-else-if=\"status.success\">Looks good!\u003C\u002Fp>\n  \u003Cul v-else>\n    \u003Cli v-for=\"e in status.errors\" :key=\"e.message\">{{ e.message }}\u003C\u002Fli>\n  \u003C\u002Ful>\n\u003C\u002Ftemplate>\n","vue",[18,337,338,361,383,398,407,411,420,442,463,475,506,515],{"__ignoreMap":33},[37,339,340,343,347,350,353,355,358],{"class":39,"line":40},[37,341,342],{"class":47},"\u003C",[37,344,346],{"class":345},"s9eBZ","script",[37,348,349],{"class":94}," setup",[37,351,352],{"class":94}," lang",[37,354,190],{"class":47},[37,356,357],{"class":54},"\"ts\"",[37,359,360],{"class":47},">\n",[37,362,363,366,368,371,373,375,377,379,381],{"class":39,"line":58},[37,364,365],{"class":43},"  const",[37,367,181],{"class":47},[37,369,370],{"class":84},"validate",[37,372,187],{"class":47},[37,374,190],{"class":43},[37,376,296],{"class":94},[37,378,299],{"class":47},[37,380,302],{"class":54},[37,382,305],{"class":47},[37,384,385,387,390,392,395],{"class":39,"line":71},[37,386,365],{"class":43},[37,388,389],{"class":84}," status",[37,391,88],{"class":43},[37,393,394],{"class":94}," validate",[37,396,397],{"class":47},"()\n",[37,399,400,403,405],{"class":39,"line":78},[37,401,402],{"class":47},"\u003C\u002F",[37,404,346],{"class":345},[37,406,360],{"class":47},[37,408,409],{"class":39,"line":101},[37,410,75],{"emptyLinePlaceholder":74},[37,412,413,415,418],{"class":39,"line":138},[37,414,342],{"class":47},[37,416,417],{"class":345},"template",[37,419,360],{"class":47},[37,421,422,425,427,430,432,435,438,440],{"class":39,"line":176},[37,423,424],{"class":47},"  \u003C",[37,426,14],{"class":345},[37,428,429],{"class":94}," v-if",[37,431,190],{"class":47},[37,433,434],{"class":54},"\"status.pending\"",[37,436,437],{"class":47},">Checking…\u003C\u002F",[37,439,14],{"class":345},[37,441,360],{"class":47},[37,443,444,446,448,451,453,456,459,461],{"class":39,"line":223},[37,445,424],{"class":47},[37,447,14],{"class":345},[37,449,450],{"class":94}," v-else-if",[37,452,190],{"class":47},[37,454,455],{"class":54},"\"status.success\"",[37,457,458],{"class":47},">Looks good!\u003C\u002F",[37,460,14],{"class":345},[37,462,360],{"class":47},[37,464,465,467,470,473],{"class":39,"line":232},[37,466,424],{"class":47},[37,468,469],{"class":345},"ul",[37,471,472],{"class":94}," v-else",[37,474,360],{"class":47},[37,476,477,480,483,486,488,491,494,496,499,502,504],{"class":39,"line":244},[37,478,479],{"class":47},"    \u003C",[37,481,482],{"class":345},"li",[37,484,485],{"class":94}," v-for",[37,487,190],{"class":47},[37,489,490],{"class":54},"\"e in status.errors\"",[37,492,493],{"class":94}," :key",[37,495,190],{"class":47},[37,497,498],{"class":54},"\"e.message\"",[37,500,501],{"class":47},">{{ e.message }}\u003C\u002F",[37,503,482],{"class":345},[37,505,360],{"class":47},[37,507,508,511,513],{"class":39,"line":265},[37,509,510],{"class":47},"  \u003C\u002F",[37,512,469],{"class":345},[37,514,360],{"class":47},[37,516,517,519,521],{"class":39,"line":271},[37,518,402],{"class":47},[37,520,417],{"class":345},[37,522,360],{"class":47},[14,524,525,526,528,529,532],{},"When the form mutates, ",[18,527,329],{}," flips back to ",[18,530,531],{},"true"," and the\nlibrary re-validates. If the user types faster than the server can\nanswer, older responses are discarded — your ref only ever shows the\nlatest result.",[23,534,536,537],{"id":535},"one-shot-validation-with-validateasyncpath","One-shot validation with ",[18,538,539],{},"validateAsync(path?)",[14,541,542,543,545],{},"For non-submit flows — a \"continue\" button on a wizard, a manual\nre-check after a server round-trip — ",[18,544,195],{}," a single validation run:",[28,547,549],{"className":30,"code":548,"language":32,"meta":33,"style":33},"const { validateAsync, errors } = useForm({ schema, key: 'signup' })\n\nasync function onContinueClick() {\n  const result = await validateAsync()\n  if (!result.success) return\n  goToNextStep()\n}\n",[18,550,551,577,581,594,610,626,633],{"__ignoreMap":33},[37,552,553,555,557,560,562,564,566,568,570,573,575],{"class":39,"line":40},[37,554,81],{"class":43},[37,556,181],{"class":47},[37,558,559],{"class":84},"validateAsync",[37,561,286],{"class":47},[37,563,289],{"class":84},[37,565,187],{"class":47},[37,567,190],{"class":43},[37,569,296],{"class":94},[37,571,572],{"class":47},"({ schema, key: ",[37,574,302],{"class":54},[37,576,305],{"class":47},[37,578,579],{"class":39,"line":58},[37,580,75],{"emptyLinePlaceholder":74},[37,582,583,585,588,591],{"class":39,"line":71},[37,584,119],{"class":43},[37,586,587],{"class":43}," function",[37,589,590],{"class":94}," onContinueClick",[37,592,593],{"class":47},"() {\n",[37,595,596,598,601,603,605,608],{"class":39,"line":78},[37,597,365],{"class":43},[37,599,600],{"class":84}," result",[37,602,88],{"class":43},[37,604,149],{"class":43},[37,606,607],{"class":94}," validateAsync",[37,609,397],{"class":47},[37,611,612,615,617,620,623],{"class":39,"line":101},[37,613,614],{"class":43},"  if",[37,616,122],{"class":47},[37,618,619],{"class":43},"!",[37,621,622],{"class":47},"result.success) ",[37,624,625],{"class":43},"return\n",[37,627,628,631],{"class":39,"line":138},[37,629,630],{"class":94},"  goToNextStep",[37,632,397],{"class":47},[37,634,635],{"class":39,"line":176},[37,636,637],{"class":47},"}\n",[14,639,640,643,644,647,648,651],{},[18,641,642],{},"validateAsync(path)"," validates the subtree at ",[18,645,646],{},"path","; ",[18,649,650],{},"validateAsync()","\nvalidates the whole form.",[23,653,655],{"id":654},"disabling-buttons-during-validation","Disabling buttons during validation",[14,657,658,661,662,664,665,667,668,670],{},[18,659,660],{},"form.meta.isValidating"," is a reactive boolean that's ",[18,663,531],{}," while\nANY validation run is in flight — submit, reactive ",[18,666,321],{},", or\n",[18,669,559],{},". Gate UI off it:",[28,672,674],{"className":333,"code":673,"language":335,"meta":33,"style":33},"\u003Cbutton :disabled=\"form.meta.isValidating || form.meta.isSubmitting\">Continue\u003C\u002Fbutton>\n",[18,675,676],{"__ignoreMap":33},[37,677,678,680,683,686,689,691,694,697,700,703,705,708,710],{"class":39,"line":40},[37,679,342],{"class":47},[37,681,682],{"class":345},"button",[37,684,685],{"class":47}," :",[37,687,688],{"class":94},"disabled",[37,690,190],{"class":47},[37,692,693],{"class":54},"\"",[37,695,696],{"class":47},"form.meta.isValidating ",[37,698,699],{"class":43},"||",[37,701,702],{"class":47}," form.meta.isSubmitting",[37,704,693],{"class":54},[37,706,707],{"class":47},">Continue\u003C\u002F",[37,709,682],{"class":345},[37,711,360],{"class":47},[23,713,715],{"id":714},"combining-with-server-errors","Combining with server errors",[14,717,718,719,723,724,727,728,731,732,735,736,739,740,745],{},"Async validation covers what the ",[720,721,722],"strong",{},"schema"," knows. Real server\nerrors (payment declined, coupon expired) still arrive after a real\nPOST — parse them via ",[18,725,726],{},"parseApiErrors"," and write them with\n",[18,729,730],{},"setFieldErrors"," in your ",[18,733,734],{},"catch",". Wire entries are\n",[18,737,738],{},"{ message, code }"," (both required); see the\n",[741,742,744],"a",{"href":743},".\u002Fserver-errors","server-errors recipe"," for the full payload\nshape.",[28,747,749],{"className":30,"code":748,"language":32,"meta":33,"style":33},"import { parseApiErrors } from 'attaform'\n\nconst onSubmit = handleSubmit(async (values) => {\n  try {\n    await $fetch('\u002Fapi\u002Fsignup', { method: 'POST', body: values })\n  } catch (err) {\n    if (err.statusCode === 422) {\n      const result = parseApiErrors(err.data, { formKey: form.key })\n      if (result.ok) {\n        setFieldErrors(result.errors)\n        focusFirstError({ preventScroll: true })\n      }\n    }\n  }\n})\n",[18,750,751,763,767,794,801,823,833,850,865,873,881,893,898,903,909],{"__ignoreMap":33},[37,752,753,755,758,760],{"class":39,"line":40},[37,754,44],{"class":43},[37,756,757],{"class":47}," { parseApiErrors } ",[37,759,51],{"class":43},[37,761,762],{"class":54}," 'attaform'\n",[37,764,765],{"class":39,"line":58},[37,766,75],{"emptyLinePlaceholder":74},[37,768,769,771,774,776,779,781,783,785,788,790,792],{"class":39,"line":71},[37,770,81],{"class":43},[37,772,773],{"class":84}," onSubmit",[37,775,88],{"class":43},[37,777,778],{"class":94}," handleSubmit",[37,780,116],{"class":47},[37,782,119],{"class":43},[37,784,122],{"class":47},[37,786,787],{"class":125},"values",[37,789,129],{"class":47},[37,791,132],{"class":43},[37,793,135],{"class":47},[37,795,796,799],{"class":39,"line":78},[37,797,798],{"class":43},"  try",[37,800,135],{"class":47},[37,802,803,806,809,811,814,817,820],{"class":39,"line":101},[37,804,805],{"class":43},"    await",[37,807,808],{"class":94}," $fetch",[37,810,116],{"class":47},[37,812,813],{"class":54},"'\u002Fapi\u002Fsignup'",[37,815,816],{"class":47},", { method: ",[37,818,819],{"class":54},"'POST'",[37,821,822],{"class":47},", body: values })\n",[37,824,825,828,830],{"class":39,"line":138},[37,826,827],{"class":47},"  } ",[37,829,734],{"class":43},[37,831,832],{"class":47}," (err) {\n",[37,834,835,838,841,844,847],{"class":39,"line":176},[37,836,837],{"class":43},"    if",[37,839,840],{"class":47}," (err.statusCode ",[37,842,843],{"class":43},"===",[37,845,846],{"class":84}," 422",[37,848,849],{"class":47},") {\n",[37,851,852,855,857,859,862],{"class":39,"line":223},[37,853,854],{"class":43},"      const",[37,856,600],{"class":84},[37,858,88],{"class":43},[37,860,861],{"class":94}," parseApiErrors",[37,863,864],{"class":47},"(err.data, { formKey: form.key })\n",[37,866,867,870],{"class":39,"line":232},[37,868,869],{"class":43},"      if",[37,871,872],{"class":47}," (result.ok) {\n",[37,874,875,878],{"class":39,"line":244},[37,876,877],{"class":94},"        setFieldErrors",[37,879,880],{"class":47},"(result.errors)\n",[37,882,883,886,889,891],{"class":39,"line":265},[37,884,885],{"class":94},"        focusFirstError",[37,887,888],{"class":47},"({ preventScroll: ",[37,890,531],{"class":84},[37,892,305],{"class":47},[37,894,895],{"class":39,"line":271},[37,896,897],{"class":47},"      }\n",[37,899,900],{"class":39,"line":276},[37,901,902],{"class":47},"    }\n",[37,904,906],{"class":39,"line":905},14,[37,907,908],{"class":47},"  }\n",[37,910,912],{"class":39,"line":911},15,[37,913,268],{"class":47},[14,915,916,919,920,922],{},[18,917,918],{},"form.meta.isSubmitting"," stays ",[18,921,531],{}," across the full handler\n(validation + server round-trip), so UI gated on it works without\nextra wiring.",[23,924,926],{"id":925},"cross-field-validation","Cross-field validation",[14,928,929,930,933],{},"Use zod's sync ",[18,931,932],{},".refine"," for rules that span fields:",[28,935,937],{"className":30,"code":936,"language":32,"meta":33,"style":33},"const schema = z\n  .object({\n    password: z.string().min(8),\n    passwordConfirmation: z.string(),\n  })\n  .refine((data) => data.password === data.passwordConfirmation, {\n    message: 'Passwords do not match',\n    path: ['passwordConfirmation'],\n  })\n",[18,938,939,951,960,977,987,992,1016,1027,1038],{"__ignoreMap":33},[37,940,941,943,946,948],{"class":39,"line":40},[37,942,81],{"class":43},[37,944,945],{"class":84}," schema",[37,947,88],{"class":43},[37,949,950],{"class":47}," z\n",[37,952,953,956,958],{"class":39,"line":58},[37,954,955],{"class":47},"  .",[37,957,95],{"class":94},[37,959,98],{"class":47},[37,961,962,965,967,969,971,973,975],{"class":39,"line":71},[37,963,964],{"class":47},"    password: z.",[37,966,250],{"class":94},[37,968,110],{"class":47},[37,970,255],{"class":94},[37,972,116],{"class":47},[37,974,260],{"class":84},[37,976,241],{"class":47},[37,978,979,982,984],{"class":39,"line":78},[37,980,981],{"class":47},"    passwordConfirmation: z.",[37,983,250],{"class":94},[37,985,986],{"class":47},"(),\n",[37,988,989],{"class":39,"line":101},[37,990,991],{"class":47},"  })\n",[37,993,994,996,998,1001,1004,1006,1008,1011,1013],{"class":39,"line":138},[37,995,955],{"class":47},[37,997,113],{"class":94},[37,999,1000],{"class":47},"((",[37,1002,1003],{"class":125},"data",[37,1005,129],{"class":47},[37,1007,132],{"class":43},[37,1009,1010],{"class":47}," data.password ",[37,1012,843],{"class":43},[37,1014,1015],{"class":47}," data.passwordConfirmation, {\n",[37,1017,1018,1021,1024],{"class":39,"line":176},[37,1019,1020],{"class":47},"    message: ",[37,1022,1023],{"class":54},"'Passwords do not match'",[37,1025,1026],{"class":47},",\n",[37,1028,1029,1032,1035],{"class":39,"line":223},[37,1030,1031],{"class":47},"    path: [",[37,1033,1034],{"class":54},"'passwordConfirmation'",[37,1036,1037],{"class":47},"],\n",[37,1039,1040],{"class":39,"line":232},[37,1041,991],{"class":47},[14,1043,1044],{},"Sync and async refines work side by side — the adapter runs both in\norder.",[23,1046,1048],{"id":1047},"discriminated-unions","Discriminated unions",[14,1050,1051],{},"Let one field decide the shape of the rest:",[28,1053,1055],{"className":30,"code":1054,"language":32,"meta":33,"style":33},"const schema = z.discriminatedUnion('type', [\n  z.object({ type: z.literal('card'), number: z.string().min(16) }),\n  z.object({ type: z.literal('bank'), routing: z.string().length(9) }),\n])\n",[18,1056,1057,1078,1113,1145],{"__ignoreMap":33},[37,1058,1059,1061,1063,1065,1067,1070,1072,1075],{"class":39,"line":40},[37,1060,81],{"class":43},[37,1062,945],{"class":84},[37,1064,88],{"class":43},[37,1066,91],{"class":47},[37,1068,1069],{"class":94},"discriminatedUnion",[37,1071,116],{"class":47},[37,1073,1074],{"class":54},"'type'",[37,1076,1077],{"class":47},", [\n",[37,1079,1080,1083,1085,1088,1091,1093,1096,1099,1101,1103,1105,1107,1110],{"class":39,"line":58},[37,1081,1082],{"class":47},"  z.",[37,1084,95],{"class":94},[37,1086,1087],{"class":47},"({ type: z.",[37,1089,1090],{"class":94},"literal",[37,1092,116],{"class":47},[37,1094,1095],{"class":54},"'card'",[37,1097,1098],{"class":47},"), number: z.",[37,1100,250],{"class":94},[37,1102,110],{"class":47},[37,1104,255],{"class":94},[37,1106,116],{"class":47},[37,1108,1109],{"class":84},"16",[37,1111,1112],{"class":47},") }),\n",[37,1114,1115,1117,1119,1121,1123,1125,1128,1131,1133,1135,1138,1140,1143],{"class":39,"line":71},[37,1116,1082],{"class":47},[37,1118,95],{"class":94},[37,1120,1087],{"class":47},[37,1122,1090],{"class":94},[37,1124,116],{"class":47},[37,1126,1127],{"class":54},"'bank'",[37,1129,1130],{"class":47},"), routing: z.",[37,1132,250],{"class":94},[37,1134,110],{"class":47},[37,1136,1137],{"class":94},"length",[37,1139,116],{"class":47},[37,1141,1142],{"class":84},"9",[37,1144,1112],{"class":47},[37,1146,1147],{"class":39,"line":78},[37,1148,1149],{"class":47},"])\n",[14,1151,1152],{},"Both Zod adapters pick the active branch from the discriminator's\ncurrent value and validate against only that branch.",[23,1154,1156],{"id":1155},"seeding-the-form-from-an-async-source","Seeding the form from an async source",[14,1158,1159,1162,1163,214],{},[18,1160,1161],{},"useForm"," itself runs synchronously — for \"fetch the user's profile,\nthen show the form pre-filled\", seed inside ",[18,1164,1165],{},"onMounted",[28,1167,1169],{"className":30,"code":1168,"language":32,"meta":33,"style":33},"const form = useForm({ schema, key: 'profile' })\n\nonMounted(async () => {\n  const profile = await $fetch('\u002Fapi\u002Fprofile')\n  form.reset(profile)\n})\n",[18,1170,1171,1189,1193,1208,1228,1239],{"__ignoreMap":33},[37,1172,1173,1175,1178,1180,1182,1184,1187],{"class":39,"line":40},[37,1174,81],{"class":43},[37,1176,1177],{"class":84}," form",[37,1179,88],{"class":43},[37,1181,296],{"class":94},[37,1183,572],{"class":47},[37,1185,1186],{"class":54},"'profile'",[37,1188,305],{"class":47},[37,1190,1191],{"class":39,"line":58},[37,1192,75],{"emptyLinePlaceholder":74},[37,1194,1195,1197,1199,1201,1204,1206],{"class":39,"line":71},[37,1196,1165],{"class":94},[37,1198,116],{"class":47},[37,1200,119],{"class":43},[37,1202,1203],{"class":47}," () ",[37,1205,132],{"class":43},[37,1207,135],{"class":47},[37,1209,1210,1212,1215,1217,1219,1221,1223,1226],{"class":39,"line":78},[37,1211,365],{"class":43},[37,1213,1214],{"class":84}," profile",[37,1216,88],{"class":43},[37,1218,149],{"class":43},[37,1220,808],{"class":94},[37,1222,116],{"class":47},[37,1224,1225],{"class":54},"'\u002Fapi\u002Fprofile'",[37,1227,173],{"class":47},[37,1229,1230,1233,1236],{"class":39,"line":101},[37,1231,1232],{"class":47},"  form.",[37,1234,1235],{"class":94},"reset",[37,1237,1238],{"class":47},"(profile)\n",[37,1240,1241],{"class":39,"line":138},[37,1242,268],{"class":47},[14,1244,1245,1248,1249,1252,1253,1256,1257,1259],{},[18,1246,1247],{},"reset(next)"," applies ",[18,1250,1251],{},"next"," over the schema's defaults — same\nprecedence rules as the ",[18,1254,1255],{},"defaultValues"," option on ",[18,1258,1161],{},".",[1261,1262,1263],"style",{},"html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}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 .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 .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}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}",{"title":33,"searchDepth":58,"depth":58,"links":1265},[1266,1267,1269,1271,1272,1273,1274,1275],{"id":25,"depth":58,"text":26},{"id":317,"depth":58,"text":1268},"Live \"checking…\" UI with validate()",{"id":535,"depth":58,"text":1270},"One-shot validation with validateAsync(path?)",{"id":654,"depth":58,"text":655},{"id":714,"depth":58,"text":715},{"id":925,"depth":58,"text":926},{"id":1047,"depth":58,"text":1048},{"id":1155,"depth":58,"text":1156},"Use z.refine(async …) anywhere in your schema — uniqueness checks,\nallow-lists, server availability. Attaform awaits the result before\ndispatching your submit handler.","md",{},"\u002Fdocs\u002Frecipes\u002Fasync-validation",{"title":5,"description":1276},"docs\u002Frecipes\u002Fasync-validation","omBQxFSaKbLqk3R1-ygm6M3rUPibRGx6DiV3J0Vu8fE",1777934136193]