[{"data":1,"prerenderedAt":1675},["ShallowReactive",2],{"content-\u002Fdocs\u002Fmultistep\u002Fuse-wizard":3},{"id":4,"title":5,"body":6,"description":1656,"extension":1657,"meta":1658,"metaRows":1659,"navigation":150,"path":1670,"seo":1671,"source":1672,"stem":1673,"__hash__":1674},"docs\u002Fdocs\u002Fmultistep\u002Fuse-wizard.md","useWizard",{"type":7,"value":8,"toc":1643},"minimark",[9,13,25,28,47,52,57,60,96,103,403,421,427,431,441,569,617,628,632,640,842,846,855,1187,1191,1197,1293,1304,1308,1355,1371,1375,1385,1443,1454,1460,1471,1515,1524,1528,1531,1575,1578,1582,1639],[10,11,5],"h1",{"id":12},"usewizard",[14,15,16],"blockquote",{},[17,18,19,20,24],"p",{},"Compose a reactive wizard from an ordered list of step slots. Each slot holds a form, an affordance key for a screen with no data collection, or a function that picks one or the other at runtime. Attaform threads the same handle through navigation, status aggregation, URL sync, and a universal ",[21,22,23],"code",{},"handleSubmit"," that validates the right scope on every call.",[26,27],"docs-meta-table",{},[17,29,30,31,34,35,38,39,42,43,46],{},"A linear three-step wizard. Each step keeps its own ",[21,32,33],{},"useForm"," call, its own schema, and its own reactive surface. The rail highlights ",[21,36,37],{},"wizard.currentStep",", the progress bar reflects ",[21,40,41],{},"wizard.progress",", and ",[21,44,45],{},"wizard.handleSubmit"," fires on the final step.",[48,49],"docs-demo",{"label":50,"slug":51},"Wizard Demo","use-wizard",[53,54,56],"h2",{"id":55},"forms-and-steps","Forms and steps",[17,58,59],{},"Attaform separates two concepts that often get conflated in multistep code:",[61,62,63,75],"ul",{},[64,65,66,67,71,72,74],"li",{},"A ",[68,69,70],"strong",{},"form"," is the artifact ",[21,73,33],{}," returns: schema, fields, values, errors, submission. The central noun of Attaform.",[64,76,66,77,80,81],{},[68,78,79],{},"step"," is a position in the wizard's sequence. Steps come in two flavors:\n",[61,82,83,89],{},[64,84,66,85,88],{},[68,86,87],{},"collection step"," holds a form. The wizard gathers data here.",[64,90,91,92,95],{},"An ",[68,93,94],{},"affordance step"," holds a bare string key, no form. The wizard uses it for screens that present rather than collect: a welcome card, a terms-and-conditions panel, a review surface, a confirmation card.",[17,97,98,99,102],{},"A wizard's ",[21,100,101],{},"steps"," list mixes the two freely. The shape of a typical onboarding flow:",[104,105,110],"pre",{"className":106,"code":107,"language":108,"meta":109,"style":109},"language-ts shiki shiki-themes github-light github-dark","import { useForm, useWizard } from 'attaform\u002Fzod'\nimport { z } from 'zod'\n\nconst shippingSchema = z.object({ address: z.string(), city: z.string() })\nconst contactSchema = z.object({ email: z.email(), phone: z.string() })\nconst paymentSchema = z.object({ cardNumber: z.string(), cvv: z.string() })\nconst billingSchema = z.object({ name: z.string(), address: z.string() })\n\nconst shipping = useForm({ schema: shippingSchema, key: 'shipping' })\nconst contact = useForm({ schema: contactSchema, key: 'contact' })\nconst payment = useForm({ schema: paymentSchema, key: 'payment' })\nconst billing = useForm({ schema: billingSchema, key: 'billing' })\n\nconst wizard = useWizard({\n  steps: ['welcome', shipping, contact, 'shipping-review', payment, billing, 'final-review'],\n})\n","ts","",[21,111,112,132,145,152,186,213,239,265,270,292,312,332,352,357,373,397],{"__ignoreMap":109},[113,114,117,121,125,128],"span",{"class":115,"line":116},"line",1,[113,118,120],{"class":119},"szBVR","import",[113,122,124],{"class":123},"sVt8B"," { useForm, useWizard } ",[113,126,127],{"class":119},"from",[113,129,131],{"class":130},"sZZnC"," 'attaform\u002Fzod'\n",[113,133,135,137,140,142],{"class":115,"line":134},2,[113,136,120],{"class":119},[113,138,139],{"class":123}," { z } ",[113,141,127],{"class":119},[113,143,144],{"class":130}," 'zod'\n",[113,146,148],{"class":115,"line":147},3,[113,149,151],{"emptyLinePlaceholder":150},true,"\n",[113,153,155,158,162,165,168,172,175,178,181,183],{"class":115,"line":154},4,[113,156,157],{"class":119},"const",[113,159,161],{"class":160},"sj4cs"," shippingSchema",[113,163,164],{"class":119}," =",[113,166,167],{"class":123}," z.",[113,169,171],{"class":170},"sScJk","object",[113,173,174],{"class":123},"({ address: z.",[113,176,177],{"class":170},"string",[113,179,180],{"class":123},"(), city: z.",[113,182,177],{"class":170},[113,184,185],{"class":123},"() })\n",[113,187,189,191,194,196,198,200,203,206,209,211],{"class":115,"line":188},5,[113,190,157],{"class":119},[113,192,193],{"class":160}," contactSchema",[113,195,164],{"class":119},[113,197,167],{"class":123},[113,199,171],{"class":170},[113,201,202],{"class":123},"({ email: z.",[113,204,205],{"class":170},"email",[113,207,208],{"class":123},"(), phone: z.",[113,210,177],{"class":170},[113,212,185],{"class":123},[113,214,216,218,221,223,225,227,230,232,235,237],{"class":115,"line":215},6,[113,217,157],{"class":119},[113,219,220],{"class":160}," paymentSchema",[113,222,164],{"class":119},[113,224,167],{"class":123},[113,226,171],{"class":170},[113,228,229],{"class":123},"({ cardNumber: z.",[113,231,177],{"class":170},[113,233,234],{"class":123},"(), cvv: z.",[113,236,177],{"class":170},[113,238,185],{"class":123},[113,240,242,244,247,249,251,253,256,258,261,263],{"class":115,"line":241},7,[113,243,157],{"class":119},[113,245,246],{"class":160}," billingSchema",[113,248,164],{"class":119},[113,250,167],{"class":123},[113,252,171],{"class":170},[113,254,255],{"class":123},"({ name: z.",[113,257,177],{"class":170},[113,259,260],{"class":123},"(), address: z.",[113,262,177],{"class":170},[113,264,185],{"class":123},[113,266,268],{"class":115,"line":267},8,[113,269,151],{"emptyLinePlaceholder":150},[113,271,273,275,278,280,283,286,289],{"class":115,"line":272},9,[113,274,157],{"class":119},[113,276,277],{"class":160}," shipping",[113,279,164],{"class":119},[113,281,282],{"class":170}," useForm",[113,284,285],{"class":123},"({ schema: shippingSchema, key: ",[113,287,288],{"class":130},"'shipping'",[113,290,291],{"class":123}," })\n",[113,293,295,297,300,302,304,307,310],{"class":115,"line":294},10,[113,296,157],{"class":119},[113,298,299],{"class":160}," contact",[113,301,164],{"class":119},[113,303,282],{"class":170},[113,305,306],{"class":123},"({ schema: contactSchema, key: ",[113,308,309],{"class":130},"'contact'",[113,311,291],{"class":123},[113,313,315,317,320,322,324,327,330],{"class":115,"line":314},11,[113,316,157],{"class":119},[113,318,319],{"class":160}," payment",[113,321,164],{"class":119},[113,323,282],{"class":170},[113,325,326],{"class":123},"({ schema: paymentSchema, key: ",[113,328,329],{"class":130},"'payment'",[113,331,291],{"class":123},[113,333,335,337,340,342,344,347,350],{"class":115,"line":334},12,[113,336,157],{"class":119},[113,338,339],{"class":160}," billing",[113,341,164],{"class":119},[113,343,282],{"class":170},[113,345,346],{"class":123},"({ schema: billingSchema, key: ",[113,348,349],{"class":130},"'billing'",[113,351,291],{"class":123},[113,353,355],{"class":115,"line":354},13,[113,356,151],{"emptyLinePlaceholder":150},[113,358,360,362,365,367,370],{"class":115,"line":359},14,[113,361,157],{"class":119},[113,363,364],{"class":160}," wizard",[113,366,164],{"class":119},[113,368,369],{"class":170}," useWizard",[113,371,372],{"class":123},"({\n",[113,374,376,379,382,385,388,391,394],{"class":115,"line":375},15,[113,377,378],{"class":123},"  steps: [",[113,380,381],{"class":130},"'welcome'",[113,383,384],{"class":123},", shipping, contact, ",[113,386,387],{"class":130},"'shipping-review'",[113,389,390],{"class":123},", payment, billing, ",[113,392,393],{"class":130},"'final-review'",[113,395,396],{"class":123},"],\n",[113,398,400],{"class":115,"line":399},16,[113,401,402],{"class":123},"})\n",[17,404,405,406,408,409,412,413,416,417,420],{},"Seven positions, four collection steps, three affordance steps. The wizard treats every position uniformly. ",[21,407,37],{}," walks the list left to right. ",[21,410,411],{},"wizard.statuses[key]"," answers for every step, with affordance steps reading as always-valid so a rail dot or progress fraction doesn't need to special-case them. Under the hood, each affordance step gets a wizard-owned noop form backed by an empty ",[21,414,415],{},"AbstractSchema"," (no fields, validates as ",[21,418,419],{},"{}","), so affordance positions participate in the same registry, status, and submission machinery as schema-backed forms without the wizard knowing about Zod (or any other adapter).",[17,422,423,424,426],{},"Affordance steps are a first-class building block, not an edge case. Onboarding flows live or die by the breathing room between dense collection screens: the welcome card that sets expectations, the review surface that lets the user check their work, the congratulations card that confirms a transaction landed. Each one is one string in the ",[21,425,101],{}," array.",[53,428,430],{"id":429},"step-slots","Step slots",[17,432,433,434,436,437,440],{},"Each entry in ",[21,435,101],{}," is a ",[68,438,439],{},"slot",". Four slot kinds compose the list:",[104,442,444],{"className":106,"code":443,"language":108,"meta":109,"style":109},"import { useForm, useWizard, lazy } from 'attaform\u002Fzod'\n\nconst wizard = useWizard({\n  steps: [\n    shipping, \u002F\u002F form slot\n    'shipping-review', \u002F\u002F affordance slot\n    (ctx) => (ctx.forms.contact.values.kind === 'business' ? billing : payment), \u002F\u002F function slot\n    lazy((ctx) => buildSummaryForm(ctx)), \u002F\u002F memoized lazy slot\n  ],\n})\n",[21,445,446,457,461,473,478,487,498,537,560,565],{"__ignoreMap":109},[113,447,448,450,453,455],{"class":115,"line":116},[113,449,120],{"class":119},[113,451,452],{"class":123}," { useForm, useWizard, lazy } ",[113,454,127],{"class":119},[113,456,131],{"class":130},[113,458,459],{"class":115,"line":134},[113,460,151],{"emptyLinePlaceholder":150},[113,462,463,465,467,469,471],{"class":115,"line":147},[113,464,157],{"class":119},[113,466,364],{"class":160},[113,468,164],{"class":119},[113,470,369],{"class":170},[113,472,372],{"class":123},[113,474,475],{"class":115,"line":154},[113,476,477],{"class":123},"  steps: [\n",[113,479,480,483],{"class":115,"line":188},[113,481,482],{"class":123},"    shipping, ",[113,484,486],{"class":485},"sJ8bj","\u002F\u002F form slot\n",[113,488,489,492,495],{"class":115,"line":215},[113,490,491],{"class":130},"    'shipping-review'",[113,493,494],{"class":123},", ",[113,496,497],{"class":485},"\u002F\u002F affordance slot\n",[113,499,500,503,507,510,513,516,519,522,525,528,531,534],{"class":115,"line":241},[113,501,502],{"class":123},"    (",[113,504,506],{"class":505},"s4XuR","ctx",[113,508,509],{"class":123},") ",[113,511,512],{"class":119},"=>",[113,514,515],{"class":123}," (ctx.forms.contact.values.kind ",[113,517,518],{"class":119},"===",[113,520,521],{"class":130}," 'business'",[113,523,524],{"class":119}," ?",[113,526,527],{"class":123}," billing ",[113,529,530],{"class":119},":",[113,532,533],{"class":123}," payment), ",[113,535,536],{"class":485},"\u002F\u002F function slot\n",[113,538,539,542,545,547,549,551,554,557],{"class":115,"line":267},[113,540,541],{"class":170},"    lazy",[113,543,544],{"class":123},"((",[113,546,506],{"class":505},[113,548,509],{"class":123},[113,550,512],{"class":119},[113,552,553],{"class":170}," buildSummaryForm",[113,555,556],{"class":123},"(ctx)), ",[113,558,559],{"class":485},"\u002F\u002F memoized lazy slot\n",[113,561,562],{"class":115,"line":272},[113,563,564],{"class":123},"  ],\n",[113,566,567],{"class":115,"line":294},[113,568,402],{"class":123},[61,570,571,580,586,604],{},[64,572,573,576,577,579],{},[68,574,575],{},"Form slot",": a form built with ",[21,578,33],{},". The wizard surfaces it as-is.",[64,581,582,585],{},[68,583,584],{},"Affordance slot",": a bare string. Becomes the step's key; the wizard generates a noop form under it.",[64,587,588,591,592,595,596,599,600,603],{},[68,589,590],{},"Function slot",": ",[21,593,594],{},"(ctx) => Form | string | undefined",". Re-evaluates reactively as ",[21,597,598],{},"ctx.forms.\u003Ckey>.values"," mutate. The picked result replaces the slot's compiled step. Returning ",[21,601,602],{},"undefined"," drops the slot.",[64,605,606,591,609,612,613,616],{},[68,607,608],{},"Lazy slot",[21,610,611],{},"lazy((ctx) => ...)",". Memoized by the resolver's tracked reactive reads. Re-fires on dep change or ",[21,614,615],{},"wizard.reset()",". Right shape for resolvers expensive enough that thrash matters.",[17,618,619,620,624,625,627],{},"See ",[621,622,430],"a",{"href":623},"\u002Fdocs\u002Fmultistep\u002Fstep-slots"," for the full slot reference, including the ",[21,626,506],{}," shape and the rules around reactive re-evaluation.",[53,629,631],{"id":630},"options","Options",[17,633,634,636,637,639],{},[21,635,5],{}," takes one options bag. ",[21,638,101],{}," is required; the rest default sensibly for the common URL-synchronized wizard case.",[641,642,643,662],"table",{},[644,645,646],"thead",{},[647,648,649,653,656,659],"tr",{},[650,651,652],"th",{},"Option",[650,654,655],{},"Type",[650,657,658],{},"Default",[650,660,661],{},"What it does",[663,664,665,686,710,733,758,786,815],"tbody",{},[647,666,667,672,677,680],{},[668,669,670],"td",{},[21,671,101],{},[668,673,674],{},[21,675,676],{},"Array\u003CStepSlot>",[668,678,679],{},"required",[668,681,682,683,685],{},"Ordered list of slots that compile into the wizard's step list. See ",[621,684,430],{"href":623},".",[647,687,688,693,697,700],{},[668,689,690],{},[21,691,692],{},"key",[668,694,695],{},[21,696,177],{},[668,698,699],{},"synthetic",[668,701,702,703,709],{},"Identifier registered in the per-app registry for ",[621,704,706],{"href":705},"\u002Fdocs\u002Fmultistep\u002Finject-wizard",[21,707,708],{},"injectWizard",". Anonymous wizards get a synthetic SSR-stable key under the hood.",[647,711,712,717,723,726],{},[668,713,714],{},[21,715,716],{},"defaultStatuses",[668,718,719,722],{},[21,720,721],{},"Record\u003Ckey, FormStatus>"," | sync factory | async factory",[668,724,725],{},"unset",[668,727,728,729,685],{},"Seed payload used while a form's defaults are still resolving. See ",[621,730,732],{"href":731},"\u002Fdocs\u002Fmultistep\u002Fstatuses","Statuses",[647,734,735,740,745,748],{},[668,736,737],{},[21,738,739],{},"progress",[668,741,742],{},[21,743,744],{},"(steps) => number",[668,746,747],{},"valid-step fraction",[668,749,750,751,753,754,757],{},"Override the default ",[21,752,739],{}," computation. The override is invoked inside a ",[21,755,756],{},"computed",", so read reactive sources only.",[647,759,760,765,770,775],{},[668,761,762],{},[21,763,764],{},"focusFirstError",[668,766,767],{},[21,768,769],{},"boolean",[668,771,772],{},[21,773,774],{},"true",[668,776,777,778,781,782,785],{},"On final-step submission failure, jump to the first failing form and run its ",[21,779,780],{},"applyInvalidSubmitPolicy()"," (focus \u002F scroll per the form's ",[21,783,784],{},"onInvalidSubmit"," configuration).",[647,787,788,793,802,808],{},[668,789,790],{},[21,791,792],{},"restore",[668,794,795,798,799],{},[21,796,797],{},"() => { step? }"," | ",[21,800,801],{},"false",[668,803,804,805],{},"URL ",[21,806,807],{},"?step=\u003Ckey>",[668,809,810,811,685],{},"Source of truth for the active step. Watched reactively; re-applies on URL changes. See ",[621,812,814],{"href":813},"\u002Fdocs\u002Fmultistep\u002Furl-sync","URL sync",[647,816,817,822,829,833],{},[668,818,819],{},[21,820,821],{},"persist",[668,823,824,798,827],{},[21,825,826],{},"({ step }) => void",[21,828,801],{},[668,830,804,831],{},[21,832,807],{},[668,834,835,836,839,840,685],{},"Destination for the active step. Invoked when ",[21,837,838],{},"currentStep"," changes (diffed to break the restore-persist loop). See ",[621,841,814],{"href":813},[53,843,845],{"id":844},"the-wizard-handle","The wizard handle",[17,847,848,850,851,854],{},[21,849,5],{}," returns a reactive handle. Every reactive read is a plain getter, no ",[21,852,853],{},".value",". Use the rail of links below to reach the page that covers each surface in depth.",[641,856,857,867],{},[644,858,859],{},[647,860,861,864],{},[650,862,863],{},"Member",[650,865,866],{},"What it is",[663,868,869,878,895,911,921,937,950,965,979,991,1003,1019,1041,1056,1069,1079,1092,1108,1120,1132,1148,1158,1170],{},[647,870,871,875],{},[668,872,873],{},[21,874,692],{},[668,876,877],{},"The wizard's identifier (explicit or synthetic).",[647,879,880,884],{},[668,881,882],{},[21,883,838],{},[668,885,886,887,889,890,798,892,894],{},"The active step's key. Typed ",[21,888,177],{}," when the slot tuple is statically non-empty; ",[21,891,177],{},[21,893,602],{}," when a function slot can drop.",[647,896,897,902],{},[668,898,899],{},[21,900,901],{},"activeForm",[668,903,904,905,908,909,685],{},"The active step's form handle, identity-equal to ",[21,906,907],{},"wizard.forms[currentStep]",". Narrows in lockstep with ",[21,910,838],{},[647,912,913,918],{},[668,914,915],{},[21,916,917],{},"activeIndex",[668,919,920],{},"Zero-based position of the active step.",[647,922,923,928],{},[668,924,925],{},[21,926,927],{},"isFinalStep",[668,929,930,932,933,936],{},[21,931,774],{}," when ",[21,934,935],{},"activeIndex === count - 1",". Gates the Next-vs-Finish split in templates.",[647,938,939,944],{},[668,940,941],{},[21,942,943],{},"count",[668,945,946,949],{},[21,947,948],{},"steps.length",". Includes affordance positions.",[647,951,952,956],{},[668,953,954],{},[21,955,101],{},[668,957,958,959,962,963,685],{},"Ordered list of compiled ",[21,960,961],{},"{ key, form }"," slots. See ",[621,964,430],{"href":623},[647,966,967,972],{},[668,968,969],{},[21,970,971],{},"forms",[668,973,974,975,685],{},"Record indexable by step key. See ",[621,976,978],{"href":977},"\u002Fdocs\u002Fmultistep\u002Faggregates","Aggregates",[647,980,981,986],{},[668,982,983],{},[21,984,985],{},"canAdvance",[668,987,988,990],{},[21,989,774],{}," when a next step exists. Pure positional check.",[647,992,993,998],{},[668,994,995],{},[21,996,997],{},"canGoBack",[668,999,1000,1002],{},[21,1001,774],{}," when a prior step exists.",[647,1004,1005,1010],{},[668,1006,1007],{},[21,1008,1009],{},"complete",[668,1011,1012,1013,1016,1017,685],{},"Forward-looking: ",[21,1014,1015],{},"isFinalStep && every-form-valid",". See ",[621,1018,732],{"href":731},[647,1020,1021,1026],{},[668,1022,1023],{},[21,1024,1025],{},"done",[668,1027,1028,1029,1031,1032,1034,1035,1038,1039,685],{},"Monotonic: ",[21,1030,774],{}," once ",[21,1033,23],{}," lands on the final step; only ",[21,1036,1037],{},"reset()"," flips it back. See ",[621,1040,732],{"href":731},[647,1042,1043,1048],{},[668,1044,1045],{},[21,1046,1047],{},"submitting",[668,1049,1050,1052,1053,1055],{},[21,1051,774],{}," while a ",[21,1054,45],{}," call is in flight. Global re-entrance guard.",[647,1057,1058,1063],{},[668,1059,1060],{},[21,1061,1062],{},"submissionAttempts",[668,1064,1065,1066,1068],{},"Count of ",[21,1067,45],{}," invocations.",[647,1070,1071,1076],{},[668,1072,1073],{},[21,1074,1075],{},"visited",[668,1077,1078],{},"Append-only breadcrumb of navigated step keys.",[647,1080,1081,1085],{},[668,1082,1083],{},[21,1084,739],{},[668,1086,1087,1088,1091],{},"Fraction in ",[21,1089,1090],{},"[0, 1]",". Defaults to valid-step ratio.",[647,1093,1094,1099],{},[668,1095,1096],{},[21,1097,1098],{},"statuses",[668,1100,1101,1102,1105,1106,685],{},"Per-key ",[21,1103,1104],{},"FormStatus"," proxy. See ",[621,1107,732],{"href":731},[647,1109,1110,1115],{},[668,1111,1112],{},[21,1113,1114],{},"allValues",[668,1116,1117,1118,685],{},"Namespaced record of each step's values. See ",[621,1119,978],{"href":977},[647,1121,1122,1127],{},[668,1123,1124],{},[21,1125,1126],{},"allErrors",[668,1128,1129,1130,685],{},"Namespaced record of each step's validation errors. See ",[621,1131,978],{"href":977},[647,1133,1134,1143],{},[668,1135,1136,1139,1140],{},[21,1137,1138],{},"next"," \u002F ",[21,1141,1142],{},"back",[668,1144,1145,1146,685],{},"Positional navigation. Refuses while ",[21,1147,1047],{},[647,1149,1150,1155],{},[668,1151,1152],{},[21,1153,1154],{},"goTo",[668,1156,1157],{},"Jump to a specific step by key. Dev-warn on unknown keys.",[647,1159,1160,1164],{},[668,1161,1162],{},[21,1163,23],{},[668,1165,1166,1167,685],{},"Universal submission handler. See ",[621,1168,23],{"href":1169},"\u002Fdocs\u002Fmultistep\u002Fhandle-submit",[647,1171,1172,1177],{},[668,1173,1174],{},[21,1175,1176],{},"reset",[668,1178,1179,1180,1183,1184,1186],{},"Zeros wizard lifecycle, resets every form, returns to ",[21,1181,1182],{},"steps[0]",", clears the persisted step, flips ",[21,1185,1025],{}," back.",[53,1188,1190],{"id":1189},"submission-in-one-place","Submission, in one place",[17,1192,1193,1196],{},[21,1194,1195],{},"wizard.handleSubmit(onSubmit, onError?)"," returns one event handler that fits every step. Intermediate calls validate the active form and advance; the final call validates every form and stays put. The same handler binds to every Next-and-Finish button.",[104,1198,1200],{"className":106,"code":1199,"language":108,"meta":109,"style":109},"const onSubmit = wizard.handleSubmit(async (ctx) => {\n  if (!ctx.isFinal) return\n  await api.checkout({\n    shipping: ctx.get(shipping),\n    payment: ctx.get(payment),\n  })\n})\n",[21,1201,1202,1234,1250,1263,1274,1284,1289],{"__ignoreMap":109},[113,1203,1204,1206,1209,1211,1214,1216,1219,1222,1225,1227,1229,1231],{"class":115,"line":116},[113,1205,157],{"class":119},[113,1207,1208],{"class":160}," onSubmit",[113,1210,164],{"class":119},[113,1212,1213],{"class":123}," wizard.",[113,1215,23],{"class":170},[113,1217,1218],{"class":123},"(",[113,1220,1221],{"class":119},"async",[113,1223,1224],{"class":123}," (",[113,1226,506],{"class":505},[113,1228,509],{"class":123},[113,1230,512],{"class":119},[113,1232,1233],{"class":123}," {\n",[113,1235,1236,1239,1241,1244,1247],{"class":115,"line":134},[113,1237,1238],{"class":119},"  if",[113,1240,1224],{"class":123},[113,1242,1243],{"class":119},"!",[113,1245,1246],{"class":123},"ctx.isFinal) ",[113,1248,1249],{"class":119},"return\n",[113,1251,1252,1255,1258,1261],{"class":115,"line":147},[113,1253,1254],{"class":119},"  await",[113,1256,1257],{"class":123}," api.",[113,1259,1260],{"class":170},"checkout",[113,1262,372],{"class":123},[113,1264,1265,1268,1271],{"class":115,"line":154},[113,1266,1267],{"class":123},"    shipping: ctx.",[113,1269,1270],{"class":170},"get",[113,1272,1273],{"class":123},"(shipping),\n",[113,1275,1276,1279,1281],{"class":115,"line":188},[113,1277,1278],{"class":123},"    payment: ctx.",[113,1280,1270],{"class":170},[113,1282,1283],{"class":123},"(payment),\n",[113,1285,1286],{"class":115,"line":215},[113,1287,1288],{"class":123},"  })\n",[113,1290,1291],{"class":115,"line":241},[113,1292,402],{"class":123},[17,1294,619,1295,1297,1298,1300,1301,1303],{},[621,1296,23],{"href":1169}," for the universal handler depth, including ",[21,1299,764],{},", re-entrance, error aggregation, and the ",[21,1302,506],{}," shape.",[53,1305,1307],{"id":1306},"navigation","Navigation",[104,1309,1311],{"className":106,"code":1310,"language":108,"meta":109,"style":109},"await wizard.next() \u002F\u002F advance one position\nwizard.back() \u002F\u002F retreat one position\nwizard.goTo('shipping-review') \u002F\u002F jump to a specific step by key\n",[21,1312,1313,1328,1340],{"__ignoreMap":109},[113,1314,1315,1318,1320,1322,1325],{"class":115,"line":116},[113,1316,1317],{"class":119},"await",[113,1319,1213],{"class":123},[113,1321,1138],{"class":170},[113,1323,1324],{"class":123},"() ",[113,1326,1327],{"class":485},"\u002F\u002F advance one position\n",[113,1329,1330,1333,1335,1337],{"class":115,"line":134},[113,1331,1332],{"class":123},"wizard.",[113,1334,1142],{"class":170},[113,1336,1324],{"class":123},[113,1338,1339],{"class":485},"\u002F\u002F retreat one position\n",[113,1341,1342,1344,1346,1348,1350,1352],{"class":115,"line":147},[113,1343,1332],{"class":123},[113,1345,1154],{"class":170},[113,1347,1218],{"class":123},[113,1349,387],{"class":130},[113,1351,509],{"class":123},[113,1353,1354],{"class":485},"\u002F\u002F jump to a specific step by key\n",[17,1356,1357,1139,1359,1139,1361,1363,1364,1366,1367,1370],{},[21,1358,1138],{},[21,1360,1142],{},[21,1362,1154],{}," are pure positional navigation. None of them validate; that's ",[21,1365,23],{},"'s job. Out-of-bounds calls dev-warn and no-op; mid-submission navigation is blocked until ",[21,1368,1369],{},"wizard.submitting"," clears. A wizard wired into a checkout or signup never throws on navigation.",[53,1372,1374],{"id":1373},"url-sync-on-by-default","URL sync, on by default",[17,1376,1377,1378,1380,1381,1384],{},"A wizard with no extra options reads its starting step from ",[21,1379,807],{}," on the URL and writes the active step back as the user navigates. Reloads land on the same step, the browser back \u002F forward buttons walk the flow, and the URL is shareable. On the server, the wizard reads the incoming request's ",[21,1382,1383],{},"?step"," so deep-links render the right step on the first byte.",[104,1386,1388],{"className":106,"code":1387,"language":108,"meta":109,"style":109},"import { useForm, useWizard } from 'attaform\u002Fzod'\n\nconst wizard = useWizard({\n  steps: ['welcome', shipping, payment, 'final-review'],\n  \u002F\u002F restore: defaults to reading ?step=\u003Ckey>\n  \u002F\u002F persist: defaults to writing ?step=\u003Ckey>\n})\n",[21,1389,1390,1400,1404,1416,1429,1434,1439],{"__ignoreMap":109},[113,1391,1392,1394,1396,1398],{"class":115,"line":116},[113,1393,120],{"class":119},[113,1395,124],{"class":123},[113,1397,127],{"class":119},[113,1399,131],{"class":130},[113,1401,1402],{"class":115,"line":134},[113,1403,151],{"emptyLinePlaceholder":150},[113,1405,1406,1408,1410,1412,1414],{"class":115,"line":147},[113,1407,157],{"class":119},[113,1409,364],{"class":160},[113,1411,164],{"class":119},[113,1413,369],{"class":170},[113,1415,372],{"class":123},[113,1417,1418,1420,1422,1425,1427],{"class":115,"line":154},[113,1419,378],{"class":123},[113,1421,381],{"class":130},[113,1423,1424],{"class":123},", shipping, payment, ",[113,1426,393],{"class":130},[113,1428,396],{"class":123},[113,1430,1431],{"class":115,"line":188},[113,1432,1433],{"class":485},"  \u002F\u002F restore: defaults to reading ?step=\u003Ckey>\n",[113,1435,1436],{"class":115,"line":215},[113,1437,1438],{"class":485},"  \u002F\u002F persist: defaults to writing ?step=\u003Ckey>\n",[113,1440,1441],{"class":115,"line":241},[113,1442,402],{"class":123},[17,1444,1445,1446,1448,1449,1451,1452,685],{},"To rename the param, scope it across multiple wizards on the same page, or wire the state to non-URL storage (localStorage, a broadcast channel, a router state field), pass ",[21,1447,792],{}," and ",[21,1450,821],{}," callbacks. See ",[621,1453,814],{"href":813},[53,1455,1457,1458],{"id":1456},"cross-component-access-with-key","Cross-component access with ",[21,1459,692],{},[17,1461,1462,1463,1465,1466,1470],{},"Pass ",[21,1464,692],{}," to give the wizard a stable identifier. Any descendant component reaches the same reactive handle through ",[621,1467,1468],{"href":705},[21,1469,708],{}," without prop-threading:",[104,1472,1474],{"className":106,"code":1473,"language":108,"meta":109,"style":109},"const wizard = useWizard({\n  steps: ['welcome', shipping, payment, 'final-review'],\n  key: 'checkout',\n})\n",[21,1475,1476,1488,1500,1511],{"__ignoreMap":109},[113,1477,1478,1480,1482,1484,1486],{"class":115,"line":116},[113,1479,157],{"class":119},[113,1481,364],{"class":160},[113,1483,164],{"class":119},[113,1485,369],{"class":170},[113,1487,372],{"class":123},[113,1489,1490,1492,1494,1496,1498],{"class":115,"line":134},[113,1491,378],{"class":123},[113,1493,381],{"class":130},[113,1495,1424],{"class":123},[113,1497,393],{"class":130},[113,1499,396],{"class":123},[113,1501,1502,1505,1508],{"class":115,"line":147},[113,1503,1504],{"class":123},"  key: ",[113,1506,1507],{"class":130},"'checkout'",[113,1509,1510],{"class":123},",\n",[113,1512,1513],{"class":115,"line":154},[113,1514,402],{"class":123},[17,1516,1517,1518,1521,1522,685],{},"Anonymous wizards (option omitted) get a synthetic SSR-stable key under the hood and remain reachable via ambient ",[21,1519,1520],{},"injectWizard()"," from descendants of the parent that called ",[21,1523,5],{},[53,1525,1527],{"id":1526},"degenerate-inputs","Degenerate inputs",[17,1529,1530],{},"Conditions that would otherwise crash the surrounding app dev-warn and degrade:",[61,1532,1533,1547,1553,1559,1567],{},[64,1534,1535,1540,1541,1543,1544,1546],{},[68,1536,1537,1538,426],{},"Empty ",[21,1539,101],{}," Dev-warns and degrades. ",[21,1542,37],{}," reads as ",[21,1545,602],{},", navigation refuses, the surrounding app keeps rendering.",[64,1548,1549,1552],{},[68,1550,1551],{},"Duplicate step keys."," First occurrence wins; later duplicates dev-warn and drop.",[64,1554,1555,1558],{},[68,1556,1557],{},"Same form ref in multiple slots."," First slot keeps the canonical position; later slots dev-warn and drop.",[64,1560,1561,1566],{},[68,1562,1563,1565],{},[21,1564,716],{}," with an unknown key."," Ignored; known entries still apply.",[64,1568,1569,1574],{},[68,1570,1571,1573],{},[21,1572,792],{}," returns a key not in the compiled steps."," Dev-warn; the wizard falls back to the first step.",[17,1576,1577],{},"A wizard wired into a signup or checkout never crashes the surrounding app for shapes that are clearly a mistake.",[53,1579,1581],{"id":1580},"where-to-next","Where to next",[61,1583,1584,1589,1596,1607,1618,1623,1632],{},[64,1585,1586,1588],{},[621,1587,430],{"href":623}," for the full slot reference (form, string, function, lazy).",[64,1590,1591,1595],{},[621,1592,1593],{"href":705},[21,1594,708],{}," for cross-component access to the wizard handle.",[64,1597,1598,1600,1601,494,1603,42,1605,685],{},[621,1599,732],{"href":731}," for the per-step rollup, ",[21,1602,716],{},[21,1604,1009],{},[21,1606,1025],{},[64,1608,1609,1611,1612,494,1614,42,1616,685],{},[621,1610,978],{"href":977}," for ",[21,1613,1114],{},[21,1615,1126],{},[21,1617,971],{},[64,1619,1620,1622],{},[621,1621,23],{"href":1169}," for the universal submission pipeline.",[64,1624,1625,1611,1627,1139,1629,1631],{},[621,1626,814],{"href":813},[21,1628,792],{},[21,1630,821],{}," and the SSR hand-off.",[64,1633,1634,1638],{},[621,1635,1637],{"href":1636},"\u002Fdocs\u002Fmultistep\u002Fpatterns","Patterns"," for branching, review surfaces, per-step persistence and undo.",[1640,1641,1642],"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 .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}",{"title":109,"searchDepth":134,"depth":134,"links":1644},[1645,1646,1647,1648,1649,1650,1651,1652,1654,1655],{"id":55,"depth":134,"text":56},{"id":429,"depth":134,"text":430},{"id":630,"depth":134,"text":631},{"id":844,"depth":134,"text":845},{"id":1189,"depth":134,"text":1190},{"id":1306,"depth":134,"text":1307},{"id":1373,"depth":134,"text":1374},{"id":1456,"depth":134,"text":1653},"Cross-component access with key",{"id":1526,"depth":134,"text":1527},{"id":1580,"depth":134,"text":1581},"useWizard takes an ordered list of step slots and produces a reactive wizard. Forms gather data, bare string keys mark affordance steps (intros, terms, review surfaces), function slots branch on live values, and lazy() memoizes heavy slots by their own tracked reactive reads. Universal handleSubmit, namespaced aggregates, automatic URL sync.","md",{},[1660,1663,1666,1668],{"label":1661,"value":1662},"Category","Composable",{"label":1664,"value":1665,"kind":21},"Signature","useWizard({ steps, ... })",{"label":430,"value":1667,"kind":21},"Form · string · function · lazy()",{"label":978,"value":1669,"kind":21},"allValues · allErrors · forms · statuses","\u002Fdocs\u002Fmultistep\u002Fuse-wizard",{"title":5,"description":1656},null,"docs\u002Fmultistep\u002Fuse-wizard","B7bmEwCcAQc79tNY9CE8W6-kl3elZUMif2PpQ1rYuTo",1780949761480]