[{"data":1,"prerenderedAt":1162},["ShallowReactive",2],{"content-\u002Fdocs\u002Fcross-cutting-state\u002Fapp-defaults":3},{"id":4,"title":5,"body":6,"description":1141,"extension":1142,"meta":1143,"metaRows":1144,"navigation":120,"path":1157,"seo":1158,"source":1159,"stem":1160,"__hash__":1161},"docs\u002Fdocs\u002Fcross-cutting-state\u002Fapp-defaults.md","App-wide defaults",{"type":7,"value":8,"toc":1127},"minimark",[9,13,25,28,43,48,53,218,222,299,317,321,324,332,336,339,456,486,490,495,681,705,716,720,748,754,767,770,913,926,930,936,1085,1092,1096,1123],[10,11,5],"h1",{"id":12},"app-wide-defaults",[14,15,16],"blockquote",{},[17,18,19,20,24],"p",{},"One plugin call sets the defaults every ",[21,22,23],"code",{},"useForm"," in the app inherits. Set the convention once, override per-form when a particular surface needs something different.",[26,27],"docs-meta-table",{},[17,29,30,31,34,35,38,39,42],{},"This page is code-only; ",[21,32,33],{},"createAttaform"," runs at app boot, before any form mounts. The demos throughout the rest of the docs implicitly use Attaform's built-in defaults (",[21,36,37],{},"validateOn: 'change'",", ",[21,40,41],{},"debounceMs: 0",", etc.); this page shows how to set your own.",[44,45,47],"h2",{"id":46},"setup","Setup",[49,50,52],"h3",{"id":51},"bare-vue-3","Bare Vue 3",[54,55,60],"pre",{"className":56,"code":57,"language":58,"meta":59,"style":59},"language-ts shiki shiki-themes github-light github-dark","\u002F\u002F main.ts\nimport { createApp } from 'vue'\nimport { createAttaform } from 'attaform'\nimport App from '.\u002FApp.vue'\n\ncreateApp(App)\n  .use(\n    createAttaform({\n      defaults: {\n        debounceMs: 100,\n        onInvalidSubmit: 'focus-first-error',\n      },\n    })\n  )\n  .mount('#app')\n","ts","",[21,61,62,71,89,102,115,122,132,144,153,159,172,183,189,195,201],{"__ignoreMap":59},[63,64,67],"span",{"class":65,"line":66},"line",1,[63,68,70],{"class":69},"sJ8bj","\u002F\u002F main.ts\n",[63,72,74,78,82,85],{"class":65,"line":73},2,[63,75,77],{"class":76},"szBVR","import",[63,79,81],{"class":80},"sVt8B"," { createApp } ",[63,83,84],{"class":76},"from",[63,86,88],{"class":87},"sZZnC"," 'vue'\n",[63,90,92,94,97,99],{"class":65,"line":91},3,[63,93,77],{"class":76},[63,95,96],{"class":80}," { createAttaform } ",[63,98,84],{"class":76},[63,100,101],{"class":87}," 'attaform'\n",[63,103,105,107,110,112],{"class":65,"line":104},4,[63,106,77],{"class":76},[63,108,109],{"class":80}," App ",[63,111,84],{"class":76},[63,113,114],{"class":87}," '.\u002FApp.vue'\n",[63,116,118],{"class":65,"line":117},5,[63,119,121],{"emptyLinePlaceholder":120},true,"\n",[63,123,125,129],{"class":65,"line":124},6,[63,126,128],{"class":127},"sScJk","createApp",[63,130,131],{"class":80},"(App)\n",[63,133,135,138,141],{"class":65,"line":134},7,[63,136,137],{"class":80},"  .",[63,139,140],{"class":127},"use",[63,142,143],{"class":80},"(\n",[63,145,147,150],{"class":65,"line":146},8,[63,148,149],{"class":127},"    createAttaform",[63,151,152],{"class":80},"({\n",[63,154,156],{"class":65,"line":155},9,[63,157,158],{"class":80},"      defaults: {\n",[63,160,162,165,169],{"class":65,"line":161},10,[63,163,164],{"class":80},"        debounceMs: ",[63,166,168],{"class":167},"sj4cs","100",[63,170,171],{"class":80},",\n",[63,173,175,178,181],{"class":65,"line":174},11,[63,176,177],{"class":80},"        onInvalidSubmit: ",[63,179,180],{"class":87},"'focus-first-error'",[63,182,171],{"class":80},[63,184,186],{"class":65,"line":185},12,[63,187,188],{"class":80},"      },\n",[63,190,192],{"class":65,"line":191},13,[63,193,194],{"class":80},"    })\n",[63,196,198],{"class":65,"line":197},14,[63,199,200],{"class":80},"  )\n",[63,202,204,206,209,212,215],{"class":65,"line":203},15,[63,205,137],{"class":80},[63,207,208],{"class":127},"mount",[63,210,211],{"class":80},"(",[63,213,214],{"class":87},"'#app'",[63,216,217],{"class":80},")\n",[49,219,221],{"id":220},"nuxt-3-4","Nuxt 3 \u002F 4",[54,223,225],{"className":56,"code":224,"language":58,"meta":59,"style":59},"\u002F\u002F nuxt.config.ts\nexport default defineNuxtConfig({\n  modules: ['attaform\u002Fnuxt'],\n  attaform: {\n    defaults: {\n      debounceMs: 100,\n      onInvalidSubmit: 'focus-first-error',\n    },\n  },\n})\n",[21,226,227,232,245,256,261,266,275,284,289,294],{"__ignoreMap":59},[63,228,229],{"class":65,"line":66},[63,230,231],{"class":69},"\u002F\u002F nuxt.config.ts\n",[63,233,234,237,240,243],{"class":65,"line":73},[63,235,236],{"class":76},"export",[63,238,239],{"class":76}," default",[63,241,242],{"class":127}," defineNuxtConfig",[63,244,152],{"class":80},[63,246,247,250,253],{"class":65,"line":91},[63,248,249],{"class":80},"  modules: [",[63,251,252],{"class":87},"'attaform\u002Fnuxt'",[63,254,255],{"class":80},"],\n",[63,257,258],{"class":65,"line":104},[63,259,260],{"class":80},"  attaform: {\n",[63,262,263],{"class":65,"line":117},[63,264,265],{"class":80},"    defaults: {\n",[63,267,268,271,273],{"class":65,"line":124},[63,269,270],{"class":80},"      debounceMs: ",[63,272,168],{"class":167},[63,274,171],{"class":80},[63,276,277,280,282],{"class":65,"line":134},[63,278,279],{"class":80},"      onInvalidSubmit: ",[63,281,180],{"class":87},[63,283,171],{"class":80},[63,285,286],{"class":65,"line":146},[63,287,288],{"class":80},"    },\n",[63,290,291],{"class":65,"line":155},[63,292,293],{"class":80},"  },\n",[63,295,296],{"class":65,"line":161},[63,297,298],{"class":80},"})\n",[17,300,301,302,305,306,309,310,313,314,316],{},"The Nuxt module surfaces the same ",[21,303,304],{},"AttaformDefaults"," type under ",[21,307,308],{},"attaform.defaults"," in your ",[21,311,312],{},"nuxt.config.ts","; no separate ",[21,315,33],{}," call needed.",[44,318,320],{"id":319},"resolution-order","Resolution order",[17,322,323],{},"Per-form > app-level > library default. Per-form always wins.",[54,325,330],{"className":326,"code":328,"language":329,"meta":59},[327],"language-text","useForm({ … })  >  createAttaform({ defaults })  >  library default\n","text",[21,331,328],{"__ignoreMap":59},[44,333,335],{"id":334},"merge-semantics","Merge semantics",[17,337,338],{},"Every option resolves independently. Set anything once at the app level, override anything per-form without losing the rest:",[54,340,342],{"className":56,"code":341,"language":58,"meta":59,"style":59},"\u002F\u002F Plugin side\ncreateAttaform({\n  defaults: { validateOn: 'change', debounceMs: 100 },\n})\n\n\u002F\u002F useForm calls\nuseForm({ schema })\n\u002F\u002F → validateOn: 'change', debounceMs: 100 (both inherited)\n\nuseForm({ schema, validateOn: 'blur' })\n\u002F\u002F → validateOn: 'blur'; debounceMs is dropped\n\u002F\u002F   (the TS-level ValidateOnConfig discriminated union rejects\n\u002F\u002F    debounceMs when validateOn isn't 'change'; paired with 'blur'\n\u002F\u002F    is a compile-time error)\n\nuseForm({ schema, debounceMs: 25 })\n\u002F\u002F → validateOn: 'change' (app-level), debounceMs: 25 (per-form wins)\n",[21,343,344,349,355,371,375,379,384,391,396,400,413,418,423,428,433,437,450],{"__ignoreMap":59},[63,345,346],{"class":65,"line":66},[63,347,348],{"class":69},"\u002F\u002F Plugin side\n",[63,350,351,353],{"class":65,"line":73},[63,352,33],{"class":127},[63,354,152],{"class":80},[63,356,357,360,363,366,368],{"class":65,"line":91},[63,358,359],{"class":80},"  defaults: { validateOn: ",[63,361,362],{"class":87},"'change'",[63,364,365],{"class":80},", debounceMs: ",[63,367,168],{"class":167},[63,369,370],{"class":80}," },\n",[63,372,373],{"class":65,"line":104},[63,374,298],{"class":80},[63,376,377],{"class":65,"line":117},[63,378,121],{"emptyLinePlaceholder":120},[63,380,381],{"class":65,"line":124},[63,382,383],{"class":69},"\u002F\u002F useForm calls\n",[63,385,386,388],{"class":65,"line":134},[63,387,23],{"class":127},[63,389,390],{"class":80},"({ schema })\n",[63,392,393],{"class":65,"line":146},[63,394,395],{"class":69},"\u002F\u002F → validateOn: 'change', debounceMs: 100 (both inherited)\n",[63,397,398],{"class":65,"line":155},[63,399,121],{"emptyLinePlaceholder":120},[63,401,402,404,407,410],{"class":65,"line":161},[63,403,23],{"class":127},[63,405,406],{"class":80},"({ schema, validateOn: ",[63,408,409],{"class":87},"'blur'",[63,411,412],{"class":80}," })\n",[63,414,415],{"class":65,"line":174},[63,416,417],{"class":69},"\u002F\u002F → validateOn: 'blur'; debounceMs is dropped\n",[63,419,420],{"class":65,"line":185},[63,421,422],{"class":69},"\u002F\u002F   (the TS-level ValidateOnConfig discriminated union rejects\n",[63,424,425],{"class":65,"line":191},[63,426,427],{"class":69},"\u002F\u002F    debounceMs when validateOn isn't 'change'; paired with 'blur'\n",[63,429,430],{"class":65,"line":197},[63,431,432],{"class":69},"\u002F\u002F    is a compile-time error)\n",[63,434,435],{"class":65,"line":203},[63,436,121],{"emptyLinePlaceholder":120},[63,438,440,442,445,448],{"class":65,"line":439},16,[63,441,23],{"class":127},[63,443,444],{"class":80},"({ schema, debounceMs: ",[63,446,447],{"class":167},"25",[63,449,412],{"class":80},[63,451,453],{"class":65,"line":452},17,[63,454,455],{"class":69},"\u002F\u002F → validateOn: 'change' (app-level), debounceMs: 25 (per-form wins)\n",[17,457,458,461,462,465,466,469,470,472,473,475,476,478,479,481,482,485],{},[21,459,460],{},"validateOn"," and ",[21,463,464],{},"debounceMs"," are flat top-level fields. The ",[21,467,468],{},"ValidateOnConfig"," discriminated union enforces that ",[21,471,464],{}," is only valid when ",[21,474,460],{}," is ",[21,477,362],{}," (or omitted); pairing it with ",[21,480,409],{}," \u002F ",[21,483,484],{},"'submit'"," doesn't compile.",[44,487,489],{"id":488},"whats-supported","What's supported",[17,491,492,494],{},[21,493,304],{}," covers the form-shaping options:",[54,496,498],{"className":56,"code":497,"language":58,"meta":59,"style":59},"type AttaformDefaults = {\n  strict?: boolean\n  validateOn?: 'change' | 'blur' | 'submit'\n  debounceMs?: number\n  onInvalidSubmit?: 'none' | 'focus-first-error' | 'scroll-to-first-error' | 'both'\n  history?: true | { max?: number }\n  rememberVariants?: boolean\n  coerce?: boolean | CoercionRegistry\n  getDisplayState?: GetDisplayState\n  maxRecursionDepth?: number\n  sensitiveNames?: readonly string[]\n  multiTab?: boolean\n}\n",[21,499,500,514,526,547,557,582,608,617,632,642,651,667,676],{"__ignoreMap":59},[63,501,502,505,508,511],{"class":65,"line":66},[63,503,504],{"class":76},"type",[63,506,507],{"class":127}," AttaformDefaults",[63,509,510],{"class":76}," =",[63,512,513],{"class":80}," {\n",[63,515,516,520,523],{"class":65,"line":73},[63,517,519],{"class":518},"s4XuR","  strict",[63,521,522],{"class":76},"?:",[63,524,525],{"class":167}," boolean\n",[63,527,528,531,533,536,539,542,544],{"class":65,"line":91},[63,529,530],{"class":518},"  validateOn",[63,532,522],{"class":76},[63,534,535],{"class":87}," 'change'",[63,537,538],{"class":76}," |",[63,540,541],{"class":87}," 'blur'",[63,543,538],{"class":76},[63,545,546],{"class":87}," 'submit'\n",[63,548,549,552,554],{"class":65,"line":104},[63,550,551],{"class":518},"  debounceMs",[63,553,522],{"class":76},[63,555,556],{"class":167}," number\n",[63,558,559,562,564,567,569,572,574,577,579],{"class":65,"line":117},[63,560,561],{"class":518},"  onInvalidSubmit",[63,563,522],{"class":76},[63,565,566],{"class":87}," 'none'",[63,568,538],{"class":76},[63,570,571],{"class":87}," 'focus-first-error'",[63,573,538],{"class":76},[63,575,576],{"class":87}," 'scroll-to-first-error'",[63,578,538],{"class":76},[63,580,581],{"class":87}," 'both'\n",[63,583,584,587,589,592,594,597,600,602,605],{"class":65,"line":124},[63,585,586],{"class":518},"  history",[63,588,522],{"class":76},[63,590,591],{"class":167}," true",[63,593,538],{"class":76},[63,595,596],{"class":80}," { ",[63,598,599],{"class":518},"max",[63,601,522],{"class":76},[63,603,604],{"class":167}," number",[63,606,607],{"class":80}," }\n",[63,609,610,613,615],{"class":65,"line":134},[63,611,612],{"class":518},"  rememberVariants",[63,614,522],{"class":76},[63,616,525],{"class":167},[63,618,619,622,624,627,629],{"class":65,"line":146},[63,620,621],{"class":518},"  coerce",[63,623,522],{"class":76},[63,625,626],{"class":167}," boolean",[63,628,538],{"class":76},[63,630,631],{"class":127}," CoercionRegistry\n",[63,633,634,637,639],{"class":65,"line":155},[63,635,636],{"class":518},"  getDisplayState",[63,638,522],{"class":76},[63,640,641],{"class":127}," GetDisplayState\n",[63,643,644,647,649],{"class":65,"line":161},[63,645,646],{"class":518},"  maxRecursionDepth",[63,648,522],{"class":76},[63,650,556],{"class":167},[63,652,653,656,658,661,664],{"class":65,"line":174},[63,654,655],{"class":518},"  sensitiveNames",[63,657,522],{"class":76},[63,659,660],{"class":76}," readonly",[63,662,663],{"class":167}," string",[63,665,666],{"class":80},"[]\n",[63,668,669,672,674],{"class":65,"line":185},[63,670,671],{"class":518},"  multiTab",[63,673,522],{"class":76},[63,675,525],{"class":167},[63,677,678],{"class":65,"line":191},[63,679,680],{"class":80},"}\n",[17,682,683,686,687,690,691,694,695,698,699,704],{},[21,684,685],{},"getDisplayState"," resolves ",[21,688,689],{},"field.displayState"," and its ",[21,692,693],{},"show*"," projections: the centralized \"what should this field surface right now?\" reducer, returning one of idle, pending, error, or success. Set it once at the app level so every form follows the same convention. To keep the default behavior but retune the anti-flash spinner timing, pass ",[21,696,697],{},"makeDefaultDisplayState({ showDelay, minVisible })",". See ",[700,701,703],"a",{"href":702},"\u002Fdocs\u002Fvalidation\u002Fshowing-errors","Display state and showing errors"," for the full contract.",[17,706,707,710,711,715],{},[21,708,709],{},"sensitiveNames"," extends the heuristic that gates persistence opt-ins and multi-tab broadcasts. See ",[700,712,714],{"href":713},"\u002Fdocs\u002Fpersistence\u002Fsensitive-names","Sensitive-name protection",".",[44,717,719],{"id":718},"whats-not-supported-and-why","What's NOT supported (and why)",[721,722,723,730,736,742],"ul",{},[724,725,726,729],"li",{},[21,727,728],{},"schema",": per-form by definition; a cross-form schema doesn't make sense.",[724,731,732,735],{},[21,733,734],{},"key",": per-form identity.",[724,737,738,741],{},[21,739,740],{},"defaultValues",": per-form initial values.",[724,743,744,747],{},[21,745,746],{},"persist",": opt-in per form already; cross-form storage defaults are ambiguous (key-prefix collisions, adapter selection).",[44,749,751,752],{"id":750},"per-form-defaultvalues","Per-form ",[21,753,740],{},[17,755,756,757,461,760,762,763,766],{},"Global defaults shape options like ",[21,758,759],{},"strict",[21,761,460],{},". Per-form initial values live on each ",[21,764,765],{},"useForm({ defaultValues })"," call.",[17,768,769],{},"Three patterns:",[54,771,773],{"className":56,"code":772,"language":58,"meta":59,"style":59},"import { unset } from 'attaform\u002Fzod'\n\n\u002F\u002F 1. Plain values: explicit defaults flow into storage and the form\n\u002F\u002F    is not blank for those leaves.\nuseForm({ schema, defaultValues: { email: 'me@example.com', count: 10 } })\n\n\u002F\u002F 2. Omit defaultValues entirely: every NUMERIC primitive leaf\n\u002F\u002F    (number, bigint) is auto-marked blank at construction. Storage\n\u002F\u002F    holds the schema's slim defaults; the form displays empty;\n\u002F\u002F    `form.errors.\u003Cpath>` reactively carries 'No value supplied' for\n\u002F\u002F    required schemas. Strings and booleans are NOT auto-marked\n\u002F\u002F    because their slim defaults match what the DOM shows natively.\nuseForm({ schema })\n\n\u002F\u002F 3. Mark any path as `unset`: leaf, container, or the whole form.\n\u002F\u002F    The runtime writes the schema's slim value at the path and adds\n\u002F\u002F    every primitive descendant to form.blankPaths.\nuseForm({ schema, defaultValues: { email: unset, count: 10 } })\nuseForm({ schema, defaultValues: { profile: unset } }) \u002F\u002F container\nuseForm({ schema, defaultValues: unset }) \u002F\u002F root\n",[21,774,775,787,791,796,801,820,824,829,834,839,844,849,854,860,864,869,874,879,891,902],{"__ignoreMap":59},[63,776,777,779,782,784],{"class":65,"line":66},[63,778,77],{"class":76},[63,780,781],{"class":80}," { unset } ",[63,783,84],{"class":76},[63,785,786],{"class":87}," 'attaform\u002Fzod'\n",[63,788,789],{"class":65,"line":73},[63,790,121],{"emptyLinePlaceholder":120},[63,792,793],{"class":65,"line":91},[63,794,795],{"class":69},"\u002F\u002F 1. Plain values: explicit defaults flow into storage and the form\n",[63,797,798],{"class":65,"line":104},[63,799,800],{"class":69},"\u002F\u002F    is not blank for those leaves.\n",[63,802,803,805,808,811,814,817],{"class":65,"line":117},[63,804,23],{"class":127},[63,806,807],{"class":80},"({ schema, defaultValues: { email: ",[63,809,810],{"class":87},"'me@example.com'",[63,812,813],{"class":80},", count: ",[63,815,816],{"class":167},"10",[63,818,819],{"class":80}," } })\n",[63,821,822],{"class":65,"line":124},[63,823,121],{"emptyLinePlaceholder":120},[63,825,826],{"class":65,"line":134},[63,827,828],{"class":69},"\u002F\u002F 2. Omit defaultValues entirely: every NUMERIC primitive leaf\n",[63,830,831],{"class":65,"line":146},[63,832,833],{"class":69},"\u002F\u002F    (number, bigint) is auto-marked blank at construction. Storage\n",[63,835,836],{"class":65,"line":155},[63,837,838],{"class":69},"\u002F\u002F    holds the schema's slim defaults; the form displays empty;\n",[63,840,841],{"class":65,"line":161},[63,842,843],{"class":69},"\u002F\u002F    `form.errors.\u003Cpath>` reactively carries 'No value supplied' for\n",[63,845,846],{"class":65,"line":174},[63,847,848],{"class":69},"\u002F\u002F    required schemas. Strings and booleans are NOT auto-marked\n",[63,850,851],{"class":65,"line":185},[63,852,853],{"class":69},"\u002F\u002F    because their slim defaults match what the DOM shows natively.\n",[63,855,856,858],{"class":65,"line":191},[63,857,23],{"class":127},[63,859,390],{"class":80},[63,861,862],{"class":65,"line":197},[63,863,121],{"emptyLinePlaceholder":120},[63,865,866],{"class":65,"line":203},[63,867,868],{"class":69},"\u002F\u002F 3. Mark any path as `unset`: leaf, container, or the whole form.\n",[63,870,871],{"class":65,"line":439},[63,872,873],{"class":69},"\u002F\u002F    The runtime writes the schema's slim value at the path and adds\n",[63,875,876],{"class":65,"line":452},[63,877,878],{"class":69},"\u002F\u002F    every primitive descendant to form.blankPaths.\n",[63,880,882,884,887,889],{"class":65,"line":881},18,[63,883,23],{"class":127},[63,885,886],{"class":80},"({ schema, defaultValues: { email: unset, count: ",[63,888,816],{"class":167},[63,890,819],{"class":80},[63,892,894,896,899],{"class":65,"line":893},19,[63,895,23],{"class":127},[63,897,898],{"class":80},"({ schema, defaultValues: { profile: unset } }) ",[63,900,901],{"class":69},"\u002F\u002F container\n",[63,903,905,907,910],{"class":65,"line":904},20,[63,906,23],{"class":127},[63,908,909],{"class":80},"({ schema, defaultValues: unset }) ",[63,911,912],{"class":69},"\u002F\u002F root\n",[17,914,915,918,919,461,922,925],{},[21,916,917],{},"unset"," works in ",[21,920,921],{},"setValue('profile', unset)",[21,923,924],{},"reset({ email: unset })"," identically: same semantic at every position.",[44,927,929],{"id":928},"alternative-userland-wrapper","Alternative: userland wrapper",[17,931,932,933,935],{},"If you need defaults but don't want to touch the plugin (third-party component library, opting in only for some forms), wrap ",[21,934,23],{}," in your project:",[54,937,939],{"className":56,"code":938,"language":58,"meta":59,"style":59},"\u002F\u002F composables\u002FuseAppForm.ts\nimport { useForm as attaformUseForm } from 'attaform\u002Fzod'\nimport type { z } from 'zod'\n\nexport function useAppForm\u003CS extends z.ZodObject>(opts: Parameters\u003Ctypeof attaformUseForm\u003CS>>[0]) {\n  return attaformUseForm({\n    validateOn: 'change',\n    debounceMs: 100,\n    ...opts,\n  })\n}\n",[21,940,941,946,963,978,982,1040,1050,1059,1068,1076,1081],{"__ignoreMap":59},[63,942,943],{"class":65,"line":66},[63,944,945],{"class":69},"\u002F\u002F composables\u002FuseAppForm.ts\n",[63,947,948,950,953,956,959,961],{"class":65,"line":73},[63,949,77],{"class":76},[63,951,952],{"class":80}," { useForm ",[63,954,955],{"class":76},"as",[63,957,958],{"class":80}," attaformUseForm } ",[63,960,84],{"class":76},[63,962,786],{"class":87},[63,964,965,967,970,973,975],{"class":65,"line":91},[63,966,77],{"class":76},[63,968,969],{"class":76}," type",[63,971,972],{"class":80}," { z } ",[63,974,84],{"class":76},[63,976,977],{"class":87}," 'zod'\n",[63,979,980],{"class":65,"line":104},[63,981,121],{"emptyLinePlaceholder":120},[63,983,984,986,989,992,995,998,1001,1004,1006,1009,1012,1015,1018,1021,1023,1026,1029,1031,1034,1037],{"class":65,"line":117},[63,985,236],{"class":76},[63,987,988],{"class":76}," function",[63,990,991],{"class":127}," useAppForm",[63,993,994],{"class":80},"\u003C",[63,996,997],{"class":127},"S",[63,999,1000],{"class":76}," extends",[63,1002,1003],{"class":127}," z",[63,1005,715],{"class":80},[63,1007,1008],{"class":127},"ZodObject",[63,1010,1011],{"class":80},">(",[63,1013,1014],{"class":518},"opts",[63,1016,1017],{"class":76},":",[63,1019,1020],{"class":127}," Parameters",[63,1022,994],{"class":80},[63,1024,1025],{"class":76},"typeof",[63,1027,1028],{"class":80}," attaformUseForm\u003C",[63,1030,997],{"class":127},[63,1032,1033],{"class":80},">>[",[63,1035,1036],{"class":167},"0",[63,1038,1039],{"class":80},"]) {\n",[63,1041,1042,1045,1048],{"class":65,"line":124},[63,1043,1044],{"class":76},"  return",[63,1046,1047],{"class":127}," attaformUseForm",[63,1049,152],{"class":80},[63,1051,1052,1055,1057],{"class":65,"line":134},[63,1053,1054],{"class":80},"    validateOn: ",[63,1056,362],{"class":87},[63,1058,171],{"class":80},[63,1060,1061,1064,1066],{"class":65,"line":146},[63,1062,1063],{"class":80},"    debounceMs: ",[63,1065,168],{"class":167},[63,1067,171],{"class":80},[63,1069,1070,1073],{"class":65,"line":155},[63,1071,1072],{"class":76},"    ...",[63,1074,1075],{"class":80},"opts,\n",[63,1077,1078],{"class":65,"line":161},[63,1079,1080],{"class":80},"  })\n",[63,1082,1083],{"class":65,"line":174},[63,1084,680],{"class":80},[17,1086,1087,1088,1091],{},"Fully equivalent for the consumer; every ",[21,1089,1090],{},"useAppForm"," call gets your defaults; per-form options still win via the spread. The plugin-level approach is idiomatic for first-party apps; the wrapper is right when you can't (or shouldn't) influence the plugin config from your call site.",[44,1093,1095],{"id":1094},"where-to-next","Where to next",[721,1097,1098,1103,1111],{},[724,1099,1100,1102],{},[700,1101,714],{"href":713},": extend the resolved list once at the app level, tighten persistence and multi-tab in one move.",[724,1104,1105,1107,1108,1110],{},[700,1106,703],{"href":702},": set the ",[21,1109,685],{}," predicate app-wide for a consistent feel across forms.",[724,1112,1113,1117,1118,461,1120,1122],{},[700,1114,1116],{"href":1115},"\u002Fdocs\u002Fvalidation\u002Fwhen-validation-runs","When validation runs",": ",[21,1119,460],{},[21,1121,464],{}," defaults shape every form in the app.",[1124,1125,1126],"style",{},"html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}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 .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}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":59,"searchDepth":73,"depth":73,"links":1128},[1129,1133,1134,1135,1136,1137,1139,1140],{"id":46,"depth":73,"text":47,"children":1130},[1131,1132],{"id":51,"depth":91,"text":52},{"id":220,"depth":91,"text":221},{"id":319,"depth":73,"text":320},{"id":334,"depth":73,"text":335},{"id":488,"depth":73,"text":489},{"id":718,"depth":73,"text":719},{"id":750,"depth":73,"text":1138},"Per-form defaultValues",{"id":928,"depth":73,"text":929},{"id":1094,"depth":73,"text":1095},"createAttaform sets app-level defaults (validateOn, debounceMs, history, coercion, sensitiveNames) that every useForm in the app inherits. Per-form options always win the merge.","md",{},[1145,1148,1151,1154],{"label":1146,"value":1147},"Category","Plugin",{"label":1149,"value":1150,"kind":21},"Bare Vue","app.use(createAttaform({ defaults }))",{"label":1152,"value":1153,"kind":21},"Nuxt","nuxt.config.ts → attaform.defaults",{"label":1155,"value":1156},"Resolution","per-form > app-level > library default","\u002Fdocs\u002Fcross-cutting-state\u002Fapp-defaults",{"title":5,"description":1141},null,"docs\u002Fcross-cutting-state\u002Fapp-defaults","ZTcYNlBQwiUIqZkJHk1mqW4Fbjupuo1Qmb2ZDg1Pj98",1780949761390]