[{"data":1,"prerenderedAt":553},["ShallowReactive",2],{"content-\u002Fdocs\u002Fgetting-started\u002Ffrom-inputs-to-submit":3},{"id":4,"title":5,"body":6,"description":538,"extension":539,"meta":540,"metaRows":541,"navigation":115,"path":548,"seo":549,"source":550,"stem":551,"__hash__":552},"docs\u002Fdocs\u002Fgetting-started\u002Ffrom-inputs-to-submit.md","From inputs to submit",{"type":7,"value":8,"toc":532},"minimark",[9,13,28,31,48,53,58,68,189,213,217,235,261,363,403,407,420,470,503,507,528],[10,11,5],"h1",{"id":12},"from-inputs-to-submit",[14,15,16],"blockquote",{},[17,18,19,23,24,27],"p",{},[20,21,22],"code",{},"handleSubmit"," waits for validation, hands you parsed values, and reports submission state through ",[20,25,26],{},"meta.submitting",".",[29,30],"docs-meta-table",{},[17,32,33,34,37,38,41,42,47],{},"The demo binds two inputs (an ",[20,35,36],{},"email"," and a ",[20,39,40],{},"newsletter"," checkbox) and wires a submit handler that runs a 1.2-second simulated API call. Submit with a valid email and the button label switches to \"Subscribing…\" while the call runs, then a toast confirms the payload. Submit with an invalid email and focus pulls to the broken field automatically. The ",[43,44,46],"a",{"href":45},"#the-submit-handler","submit handler"," section below walks through the gating contract that produces that behavior.",[49,50],"docs-demo",{"label":51,"slug":52},"Submit Demo","inputs-to-submit",[54,55,57],"h2",{"id":56},"setting-up-the-form","Setting up the form",[17,59,60,61,63,64,67],{},"This page focuses on two helpers off the form: ",[20,62,22],{}," (the submit-wrapping factory) and ",[20,65,66],{},"meta"," (the form's reactive status board). Hoist the schema and save the form:",[69,70,75],"pre",{"className":71,"code":72,"language":73,"meta":74,"style":74},"language-ts shiki shiki-themes github-light github-dark","import { useForm } from 'attaform\u002Fzod'\nimport { z } from 'zod'\n\nconst schema = z.object({\n  email: z.email(),\n  newsletter: z.boolean(),\n})\n\nconst form = useForm({ schema })\n","ts","",[20,76,77,97,110,117,140,151,162,168,173],{"__ignoreMap":74},[78,79,82,86,90,93],"span",{"class":80,"line":81},"line",1,[78,83,85],{"class":84},"szBVR","import",[78,87,89],{"class":88},"sVt8B"," { useForm } ",[78,91,92],{"class":84},"from",[78,94,96],{"class":95},"sZZnC"," 'attaform\u002Fzod'\n",[78,98,100,102,105,107],{"class":80,"line":99},2,[78,101,85],{"class":84},[78,103,104],{"class":88}," { z } ",[78,106,92],{"class":84},[78,108,109],{"class":95}," 'zod'\n",[78,111,113],{"class":80,"line":112},3,[78,114,116],{"emptyLinePlaceholder":115},true,"\n",[78,118,120,123,127,130,133,137],{"class":80,"line":119},4,[78,121,122],{"class":84},"const",[78,124,126],{"class":125},"sj4cs"," schema",[78,128,129],{"class":84}," =",[78,131,132],{"class":88}," z.",[78,134,136],{"class":135},"sScJk","object",[78,138,139],{"class":88},"({\n",[78,141,143,146,148],{"class":80,"line":142},5,[78,144,145],{"class":88},"  email: z.",[78,147,36],{"class":135},[78,149,150],{"class":88},"(),\n",[78,152,154,157,160],{"class":80,"line":153},6,[78,155,156],{"class":88},"  newsletter: z.",[78,158,159],{"class":135},"boolean",[78,161,150],{"class":88},[78,163,165],{"class":80,"line":164},7,[78,166,167],{"class":88},"})\n",[78,169,171],{"class":80,"line":170},8,[78,172,116],{"emptyLinePlaceholder":115},[78,174,176,178,181,183,186],{"class":80,"line":175},9,[78,177,122],{"class":84},[78,179,180],{"class":125}," form",[78,182,129],{"class":84},[78,184,185],{"class":135}," useForm",[78,187,188],{"class":88},"({ schema })\n",[17,190,191,192,195,196,199,200,199,203,206,207,209,210,212],{},"The same ",[20,193,194],{},"form"," carries every helper from earlier pages (",[20,197,198],{},"register",", ",[20,201,202],{},"fields",[20,204,205],{},"values","). Only ",[20,208,22],{}," and ",[20,211,66],{}," are new here.",[54,214,216],{"id":215},"the-submit-handler","The submit handler",[17,218,219,222,223,226,227,230,231,234],{},[20,220,221],{},"handleSubmit(onSubmit, onError?)"," returns a function you bind to ",[20,224,225],{},"\u003Cform @submit>",". The wrapper calls ",[20,228,229],{},"preventDefault"," internally, so the ",[20,232,233],{},".prevent"," modifier on the template is unnecessary. When the wrapped handler fires, it:",[236,237,238,242,245,255],"ul",{},[239,240,241],"li",{},"Runs sync and async validation on every active path.",[239,243,244],{},"Waits for pending async refinements before dispatching.",[239,246,247,248,251,252,254],{},"Calls ",[20,249,250],{},"onSubmit(values)"," only if validation passes. ",[20,253,205],{}," is the parsed Zod output, fully typed.",[239,256,247,257,260],{},[20,258,259],{},"onError(errors)"," if validation fails. By default, focus moves to the first invalid field.",[69,262,264],{"className":71,"code":263,"language":73,"meta":74,"style":74},"const onSubmit = form.handleSubmit(\n  async (values) => {\n    await api.signup(values)\n  },\n  (errors) => {\n    console.log('Validation failed', errors)\n  }\n)\n",[20,265,266,283,303,317,322,336,353,358],{"__ignoreMap":74},[78,267,268,270,273,275,278,280],{"class":80,"line":81},[78,269,122],{"class":84},[78,271,272],{"class":125}," onSubmit",[78,274,129],{"class":84},[78,276,277],{"class":88}," form.",[78,279,22],{"class":135},[78,281,282],{"class":88},"(\n",[78,284,285,288,291,294,297,300],{"class":80,"line":99},[78,286,287],{"class":84},"  async",[78,289,290],{"class":88}," (",[78,292,205],{"class":293},"s4XuR",[78,295,296],{"class":88},") ",[78,298,299],{"class":84},"=>",[78,301,302],{"class":88}," {\n",[78,304,305,308,311,314],{"class":80,"line":112},[78,306,307],{"class":84},"    await",[78,309,310],{"class":88}," api.",[78,312,313],{"class":135},"signup",[78,315,316],{"class":88},"(values)\n",[78,318,319],{"class":80,"line":119},[78,320,321],{"class":88},"  },\n",[78,323,324,327,330,332,334],{"class":80,"line":142},[78,325,326],{"class":88},"  (",[78,328,329],{"class":293},"errors",[78,331,296],{"class":88},[78,333,299],{"class":84},[78,335,302],{"class":88},[78,337,338,341,344,347,350],{"class":80,"line":153},[78,339,340],{"class":88},"    console.",[78,342,343],{"class":135},"log",[78,345,346],{"class":88},"(",[78,348,349],{"class":95},"'Validation failed'",[78,351,352],{"class":88},", errors)\n",[78,354,355],{"class":80,"line":164},[78,356,357],{"class":88},"  }\n",[78,359,360],{"class":80,"line":170},[78,361,362],{"class":88},")\n",[69,364,368],{"className":365,"code":366,"language":367,"meta":74,"style":74},"language-vue shiki shiki-themes github-light github-dark","\u003Cform @submit=\"onSubmit\">…\u003C\u002Fform>\n","vue",[20,369,370],{"__ignoreMap":74},[78,371,372,375,378,381,384,387,390,393,395,398,400],{"class":80,"line":81},[78,373,374],{"class":88},"\u003C",[78,376,194],{"class":377},"s9eBZ",[78,379,380],{"class":88}," @",[78,382,383],{"class":135},"submit",[78,385,386],{"class":88},"=",[78,388,389],{"class":95},"\"",[78,391,392],{"class":88},"onSubmit",[78,394,389],{"class":95},[78,396,397],{"class":88},">…\u003C\u002F",[78,399,194],{"class":377},[78,401,402],{"class":88},">\n",[54,404,406],{"id":405},"formmetasubmitting","form.meta.submitting",[17,408,409,410,412,413,415,416,419],{},"While ",[20,411,392],{}," is running, ",[20,414,406],{}," is ",[20,417,418],{},"true",". Use it to disable the submit button or surface a spinner:",[69,421,423],{"className":365,"code":422,"language":367,"meta":74,"style":74},"\u003Cbutton :disabled=\"form.meta.submitting\" type=\"submit\">\n  {{ form.meta.submitting ? 'Saving…' : 'Save' }}\n\u003C\u002Fbutton>\n",[20,424,425,456,461],{"__ignoreMap":74},[78,426,427,429,432,435,438,440,442,444,446,449,451,454],{"class":80,"line":81},[78,428,374],{"class":88},[78,430,431],{"class":377},"button",[78,433,434],{"class":88}," :",[78,436,437],{"class":135},"disabled",[78,439,386],{"class":88},[78,441,389],{"class":95},[78,443,406],{"class":88},[78,445,389],{"class":95},[78,447,448],{"class":135}," type",[78,450,386],{"class":88},[78,452,453],{"class":95},"\"submit\"",[78,455,402],{"class":88},[78,457,458],{"class":80,"line":99},[78,459,460],{"class":88},"  {{ form.meta.submitting ? 'Saving…' : 'Save' }}\n",[78,462,463,466,468],{"class":80,"line":112},[78,464,465],{"class":88},"\u003C\u002F",[78,467,431],{"class":377},[78,469,402],{"class":88},[17,471,472,475,476,479,480,482,483,485,486,199,489,199,492,495,496,27],{},[20,473,474],{},"submitting"," flips back to ",[20,477,478],{},"false"," when the callback resolves or rejects (",[20,481,22],{}," catches the rejection and routes the failure to its error hook). The full ",[20,484,66],{}," surface (",[20,487,488],{},"submissionAttempts",[20,490,491],{},"submitError",[20,493,494],{},"submitted",", and the 22 inherited FieldState bits) lives on ",[43,497,499,500,502],{"href":498},"\u002Fdocs\u002Freading-the-form\u002Fmeta","the ",[20,501,66],{}," page",[54,504,506],{"id":505},"where-to-next","Where to next",[236,508,509,517],{},[239,510,511,516],{},[43,512,514],{"href":513},"\u002Fdocs\u002Fsubmitting\u002Fhandle-submit",[20,515,22],{},": the full submit surface, including error handlers and event semantics.",[239,518,519,523,524,527],{},[43,520,522],{"href":521},"\u002Fdocs\u002Freading-the-form\u002Fthe-form","The form",": every method and property ",[20,525,526],{},"useForm"," returns.",[529,530,531],"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 .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}html pre.shiki code .s9eBZ, html code.shiki .s9eBZ{--shiki-default:#22863A;--shiki-dark:#85E89D}",{"title":74,"searchDepth":99,"depth":99,"links":533},[534,535,536,537],{"id":56,"depth":99,"text":57},{"id":215,"depth":99,"text":216},{"id":405,"depth":99,"text":406},{"id":505,"depth":99,"text":506},"Wire a submit handler to a typed form. handleSubmit gates dispatch on validation, exposes the parsed values, and reports back through meta.submitting.","md",{},[542,545],{"label":543,"value":544},"Read time","~4 minutes",{"label":546,"value":547},"Builds on","From schema to inputs","\u002Fdocs\u002Fgetting-started\u002Ffrom-inputs-to-submit",{"title":5,"description":538},null,"docs\u002Fgetting-started\u002Ffrom-inputs-to-submit","OF4jRjAjnztOg296sqGoW0R_bFf6HW8CQFXNwliwMCM",1780949756935]