[{"data":1,"prerenderedAt":749},["ShallowReactive",2],{"content-\u002Fdocs\u002Fbinding-inputs\u002Fv-register":3},{"id":4,"title":5,"body":6,"description":731,"extension":732,"meta":733,"metaRows":734,"navigation":743,"path":744,"seo":745,"source":746,"stem":747,"__hash__":748},"docs\u002Fdocs\u002Fbinding-inputs\u002Fv-register.md","The v-register directive",{"type":7,"value":8,"toc":720},"minimark",[9,19,30,33,46,50,54,57,110,113,185,189,195,221,225,240,298,313,317,328,400,409,422,427,440,520,537,541,547,591,594,598,605,626,637,641,716],[10,11,13,14,18],"h1",{"id":12},"the-v-register-directive","The ",[15,16,17],"code",{},"v-register"," directive",[20,21,22],"blockquote",{},[23,24,25,26,29],"p",{},"One directive binds a native input to a schema path. The ",[15,27,28],{},"\u003Cinput>"," stays native; Attaform sits at the directive layer.",[31,32],"docs-meta-table",{},[23,34,35,36,39,40,45],{},"Click the input, type a few characters, blur, refocus. The four ",[15,37,38],{},"form.fields.email.*"," bits in the table below flip with each interaction. The directive surfaces every signal the schema-aware layer needs without you wiring a single event listener; the ",[41,42,44],"a",{"href":43},"#what-it-does","What it does"," section unpacks the four pieces of plumbing.",[47,48],"docs-demo",{"label":49,"slug":17},"v-register Demo",[51,52,44],"h2",{"id":53},"what-it-does",[23,55,56],{},"Bind any native input to a schema path:",[58,59,64],"pre",{"className":60,"code":61,"language":62,"meta":63,"style":63},"language-vue shiki shiki-themes github-light github-dark","\u003Cinput v-register=\"form.register('email')\" \u002F>\n","vue","",[15,65,66],{"__ignoreMap":63},[67,68,71,75,79,83,86,90,93,96,99,102,105,107],"span",{"class":69,"line":70},"line",1,[67,72,74],{"class":73},"sVt8B","\u003C",[67,76,78],{"class":77},"s9eBZ","input",[67,80,82],{"class":81},"sScJk"," v-register",[67,84,85],{"class":73},"=",[67,87,89],{"class":88},"sZZnC","\"",[67,91,92],{"class":73},"form.",[67,94,95],{"class":81},"register",[67,97,98],{"class":73},"(",[67,100,101],{"class":88},"'email'",[67,103,104],{"class":73},")",[67,106,89],{"class":88},[67,108,109],{"class":73}," \u002F>\n",[23,111,112],{},"The directive runs four pieces of plumbing for you:",[114,115,116,128,148,162],"ol",{},[117,118,119,123,124,127],"li",{},[120,121,122],"strong",{},"Reads"," the current value from ",[15,125,126],{},"form.values.\u003Cpath>"," and writes it into the DOM input on initial render and on every reactive update.",[117,129,130,133,134,136,137,139,140,143,144,147],{},[120,131,132],{},"Writes"," back to ",[15,135,126],{}," on every ",[15,138,78],{}," event (or ",[15,141,142],{},"change"," \u002F ",[15,145,146],{},"blur"," with modifiers).",[117,149,150,153,154,157,158,161],{},[120,151,152],{},"Coerces"," the DOM string to the schema's leaf type: ",[15,155,156],{},"type=\"number\""," inputs land in storage as a number, checkboxes as a boolean, radio groups pick the option ",[15,159,160],{},"value",".",[117,163,164,167,168,171,172,171,175,171,178,181,182,161],{},[120,165,166],{},"Tracks"," field state (",[15,169,170],{},"touched",", ",[15,173,174],{},"focused",[15,176,177],{},"blurred",[15,179,180],{},"blank",") and surfaces it through ",[15,183,184],{},"form.fields.\u003Cpath>",[51,186,188],{"id":187},"auto-installed","Auto-installed",[23,190,191,194],{},[15,192,193],{},"createAttaform()"," registers the directive globally, in bare Vue and in Nuxt. You don't import it.",[23,196,197,198,201,202,208,209,211,212,218,219,161],{},"If you wrap inputs inside a component whose root is ",[120,199,200],{},"not"," the input itself, ",[41,203,205],{"href":204},"\u002Fdocs\u002Fbinding-inputs\u002Fuse-register",[15,206,207],{},"useRegister"," re-binds ",[15,210,17],{}," onto an inner native element. For compound components binding multiple paths, prefer ",[41,213,215],{"href":214},"\u002Fdocs\u002Freading-the-form\u002Fthe-form",[15,216,217],{},"injectForm"," over ",[15,220,207],{},[51,222,224],{"id":223},"reading-errors-per-field","Reading errors per field",[23,226,227,228,231,232,235,236,239],{},"The directive's binding pair is read-and-error: ",[15,229,230],{},"form.register('email')"," for the input, ",[15,233,234],{},"form.fields.email.firstError?.message"," for the message, gated by ",[15,237,238],{},"form.fields.email.showErrors"," so a half-typed value doesn't get yelled at on first paint.",[58,241,243],{"className":60,"code":242,"language":62,"meta":63,"style":63},"\u003Cinput v-register=\"form.register('email')\" \u002F>\n\u003Cp v-if=\"form.fields.email.showErrors\">{{ form.fields.email.firstError?.message }}\u003C\u002Fp>\n",[15,244,245,271],{"__ignoreMap":63},[67,246,247,249,251,253,255,257,259,261,263,265,267,269],{"class":69,"line":70},[67,248,74],{"class":73},[67,250,78],{"class":77},[67,252,82],{"class":81},[67,254,85],{"class":73},[67,256,89],{"class":88},[67,258,92],{"class":73},[67,260,95],{"class":81},[67,262,98],{"class":73},[67,264,101],{"class":88},[67,266,104],{"class":73},[67,268,89],{"class":88},[67,270,109],{"class":73},[67,272,274,276,278,282,284,286,288,290,293,295],{"class":69,"line":273},2,[67,275,74],{"class":73},[67,277,23],{"class":77},[67,279,281],{"class":280},"szBVR"," v-if",[67,283,85],{"class":73},[67,285,89],{"class":88},[67,287,238],{"class":73},[67,289,89],{"class":88},[67,291,292],{"class":73},">{{ form.fields.email.firstError?.message }}\u003C\u002F",[67,294,23],{"class":77},[67,296,297],{"class":73},">\n",[23,299,300,301,304,305,308,309,312],{},"The raw ",[15,302,303],{},"form.errors.email"," Proxy stays available as ",[15,306,307],{},"ValidationError[]"," when you need the full array, empty when the field is valid. ",[15,310,311],{},"form.fields"," is the display-ergonomics layer over the same data.",[51,314,316],{"id":315},"accessibility-handled","Accessibility, handled",[23,318,319,320,322,323,327],{},"By default, ",[15,321,17],{}," keeps a field's aria attributes in sync with its ",[41,324,326],{"href":325},"\u002Fdocs\u002Fvalidation\u002Fshowing-errors","display state",", so assistive technology announces exactly what sighted users see, with no extra wiring:",[329,330,331,344],"table",{},[332,333,334],"thead",{},[335,336,337,341],"tr",{},[338,339,340],"th",{},"Attribute",[338,342,343],{},"Set when",[345,346,347,365,380,390],"tbody",{},[335,348,349,355],{},[350,351,352],"td",{},[15,353,354],{},"aria-invalid",[350,356,357,358,361,362],{},"the field's ",[15,359,360],{},"displayState"," is ",[15,363,364],{},"'error'",[335,366,367,372],{},[350,368,369],{},[15,370,371],{},"aria-busy",[350,373,357,374,361,376,379],{},[15,375,360],{},[15,377,378],{},"'pending'"," (an async check is running)",[335,381,382,387],{},[350,383,384],{},[15,385,386],{},"aria-required",[350,388,389],{},"the schema marks the path required",[335,391,392,397],{},[350,393,394],{},[15,395,396],{},"aria-describedby",[350,398,399],{},"points at the field's error id while in the error state",[23,401,402,403,405,406,408],{},"These track the same gated ",[15,404,360],{}," that drives ",[15,407,238],{},", so the announcement and the visible message reveal together, never on a half-typed value. The required and invalid states are emitted during SSR too, so a server-rendered form is accessible before hydration.",[23,410,411,413,414,416,417,421],{},[15,412,386],{}," is scoped with care. A checkbox that rolls up into an array or set group never carries it, since no single box is required on its own and an empty selection is valid; the requirement lives on the group. And every attribute lands on the real form control: when ",[15,415,17],{}," is on a wrapper component, the attributes follow the inner element it re-binds with ",[41,418,419],{"href":204},[15,420,207],{},", never the presentational root.",[423,424,426],"h3",{"id":425},"wiring-the-error-element","Wiring the error element",[23,428,429,430,432,433,439],{},"Auto-aria sets ",[15,431,396],{}," to ",[41,434,436],{"href":435},"\u002Fdocs\u002Freading-the-form\u002Ffields",[15,437,438],{},"form.fields.\u003Cpath>.aria.errorId",". Put that id on your error element so the reference resolves:",[58,441,443],{"className":60,"code":442,"language":62,"meta":63,"style":63},"\u003Cinput v-register=\"form.register('email')\" \u002F>\n\u003Cp v-if=\"form.fields.email.showErrors\" :id=\"form.fields.email.aria.errorId\">\n  {{ form.fields.email.firstError?.message }}\n\u003C\u002Fp>\n",[15,444,445,471,504,510],{"__ignoreMap":63},[67,446,447,449,451,453,455,457,459,461,463,465,467,469],{"class":69,"line":70},[67,448,74],{"class":73},[67,450,78],{"class":77},[67,452,82],{"class":81},[67,454,85],{"class":73},[67,456,89],{"class":88},[67,458,92],{"class":73},[67,460,95],{"class":81},[67,462,98],{"class":73},[67,464,101],{"class":88},[67,466,104],{"class":73},[67,468,89],{"class":88},[67,470,109],{"class":73},[67,472,473,475,477,479,481,483,485,487,490,493,495,497,500,502],{"class":69,"line":273},[67,474,74],{"class":73},[67,476,23],{"class":77},[67,478,281],{"class":280},[67,480,85],{"class":73},[67,482,89],{"class":88},[67,484,238],{"class":73},[67,486,89],{"class":88},[67,488,489],{"class":73}," :",[67,491,492],{"class":81},"id",[67,494,85],{"class":73},[67,496,89],{"class":88},[67,498,499],{"class":73},"form.fields.email.aria.errorId",[67,501,89],{"class":88},[67,503,297],{"class":73},[67,505,507],{"class":69,"line":506},3,[67,508,509],{"class":73},"  {{ form.fields.email.firstError?.message }}\n",[67,511,513,516,518],{"class":69,"line":512},4,[67,514,515],{"class":73},"\u003C\u002F",[67,517,23],{"class":77},[67,519,297],{"class":73},[23,521,522,524,525,528,529,532,533,536],{},[15,523,499],{}," is stable for the field and unique across every mount on the page (it folds in the form's ",[15,526,527],{},"instanceId","), so two instances of the same form never cross their references. The companion ",[15,530,531],{},"form.fields.email.id"," wires a ",[15,534,535],{},"\u003Clabel :for>"," to the input when you need one.",[423,538,540],{"id":539},"respect-your-markup","Respect your markup",[23,542,543,544,546],{},"Write any aria attribute yourself and Attaform leaves it alone, for that one attribute. Author ",[15,545,354],{}," while the other three stay automatic:",[58,548,550],{"className":60,"code":549,"language":62,"meta":63,"style":63},"\u003Cinput v-register=\"form.register('email')\" :aria-invalid=\"hasCustomError\" \u002F>\n",[15,551,552],{"__ignoreMap":63},[67,553,554,556,558,560,562,564,566,568,570,572,574,576,578,580,582,584,587,589],{"class":69,"line":70},[67,555,74],{"class":73},[67,557,78],{"class":77},[67,559,82],{"class":81},[67,561,85],{"class":73},[67,563,89],{"class":88},[67,565,92],{"class":73},[67,567,95],{"class":81},[67,569,98],{"class":73},[67,571,101],{"class":88},[67,573,104],{"class":73},[67,575,89],{"class":88},[67,577,489],{"class":73},[67,579,354],{"class":81},[67,581,85],{"class":73},[67,583,89],{"class":88},[67,585,586],{"class":73},"hasCustomError",[67,588,89],{"class":88},[67,590,109],{"class":73},[23,592,593],{},"The check happens per attribute and per binding, so reaching for one escape hatch never disables the rest.",[423,595,597],{"id":596},"turning-it-off","Turning it off",[23,599,600,601,604],{},"One knob, ",[15,602,603],{},"autoAria",", at three tiers; the narrower tier wins:",[606,607,608,614,620],"ul",{},[117,609,610,611,161],{},"Per binding: ",[15,612,613],{},"form.register('email', { autoAria: false })",[117,615,616,617,161],{},"Per form: ",[15,618,619],{},"useForm({ schema, autoAria: false })",[117,621,622,623,161],{},"App-wide: ",[15,624,625],{},"createAttaform({ defaults: { autoAria: false } })",[23,627,628,629,632,633,636],{},"A narrower tier overrides the wider one in either direction, so a single binding can re-enable management with ",[15,630,631],{},"{ autoAria: true }"," even when the form opted out. Any tier set to ",[15,634,635],{},"false"," hands every aria attribute back to your markup; an authored attribute is always preserved regardless.",[51,638,640],{"id":639},"where-to-next","Where to next",[606,642,643,653,670,677,686,695,710],{},[117,644,645,649,650,652],{},[41,646,647],{"href":204},[15,648,207],{},": the composable for re-binding ",[15,651,17],{}," onto an inner native element inside a wrapper component.",[117,654,655,659,660,171,663,171,666,669],{},[41,656,658],{"href":657},"\u002Fdocs\u002Fbinding-inputs\u002Fmodifiers","Modifiers",": ",[15,661,662],{},".lazy",[15,664,665],{},".trim",[15,667,668],{},".number"," for tuning the write side.",[117,671,672,676],{},[41,673,675],{"href":674},"\u002Fdocs\u002Fbinding-inputs\u002Fcoercion","Schema-driven coercion",": how DOM strings land at the right leaf type.",[117,678,679,685],{},[41,680,682],{"href":681},"\u002Fdocs\u002Freading-the-form\u002Fvalues",[15,683,684],{},"values",": what the directive writes into.",[117,687,688,694],{},[41,689,691],{"href":690},"\u002Fdocs\u002Freading-the-form\u002Ferrors",[15,692,693],{},"errors",": the error reads paired with each registered path.",[117,696,697,702,703,705,706,709],{},[41,698,699],{"href":435},[15,700,701],{},"fields",": the ",[15,704,492],{}," and ",[15,707,708],{},"aria"," ids the accessibility wiring reads from.",[117,711,712,715],{},[41,713,714],{"href":325},"Display state and showing errors",": the gated verdict the aria attributes track.",[717,718,719],"style",{},"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 .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 .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}",{"title":63,"searchDepth":273,"depth":273,"links":721},[722,723,724,725,730],{"id":53,"depth":273,"text":44},{"id":187,"depth":273,"text":188},{"id":223,"depth":273,"text":224},{"id":315,"depth":273,"text":316,"children":726},[727,728,729],{"id":425,"depth":506,"text":426},{"id":539,"depth":506,"text":540},{"id":596,"depth":506,"text":597},{"id":639,"depth":273,"text":640},"v-register binds a native input to a schema path. The directive handles the value sync, the coercion, the dirty-tracking, and the focus pass while your input stays native.","md",{},[735,738,741],{"label":736,"value":737},"Category","Directive",{"label":739,"value":740},"Element","input \u002F select \u002F textarea \u002F file",{"label":188,"value":742},"Yes",true,"\u002Fdocs\u002Fbinding-inputs\u002Fv-register",{"title":5,"description":731},null,"docs\u002Fbinding-inputs\u002Fv-register","gygIo6JwvOqNFYD0Nakl2SrUTsCkT38IL0MOt-rhL30",1781745872070]