[{"data":1,"prerenderedAt":683},["ShallowReactive",2],{"content-\u002Fdocs\u002Freading-the-form\u002Frecord":3},{"id":4,"title":5,"body":6,"description":665,"extension":666,"meta":667,"metaRows":668,"navigation":147,"path":678,"seo":679,"source":680,"stem":681,"__hash__":682},"docs\u002Fdocs\u002Freading-the-form\u002Frecord.md","record",{"type":7,"value":8,"toc":653},"minimark",[9,15,30,33,57,62,67,74,349,362,366,399,403,413,441,444,451,471,478,493,567,574,580,600,604,649],[10,11,12],"h1",{"id":5},[13,14,5],"code",{},[16,17,18],"blockquote",{},[19,20,21,22,25,26,29],"p",{},"One record, one FieldState per entry, keyed by the entry's own key. Iterate it with ",[13,23,24],{},"v-for=\"(field, key) in form.record(path)\""," and bind ",[13,27,28],{},":key=\"key\"",".",[31,32],"docs-meta-table",{},[19,34,35,38,39,46,47,49,50,56],{},[13,36,37],{},"form.record(path)"," is the iteration view over a record. Where ",[40,41,43],"a",{"href":42},"\u002Fdocs\u002Freading-the-form\u002Flist",[13,44,45],{},"list"," hands back an ordered array for an array path, ",[13,48,5],{}," hands back a keyed object for a record path: one ",[40,51,53],{"href":52},"\u002Fdocs\u002Freading-the-form\u002Ffields",[13,54,55],{},"FieldState"," per entry, under the entry's own key. Reach for it whenever the keys are the data, set at run time rather than declared in the schema.",[58,59],"docs-demo",{"label":60,"slug":61},"form.record Demo","form-record",[63,64,66],"h2",{"id":65},"iterating-a-record","Iterating a record",[19,68,69,70,73],{},"Declare the record on your schema, then iterate ",[13,71,72],{},"form.record"," by its key. The keys come from the form, so you render whatever entries exist without keeping a parallel list of your own:",[75,76,81],"pre",{"className":77,"code":78,"language":79,"meta":80,"style":80},"language-vue shiki shiki-themes github-light github-dark","\u003Cscript setup lang=\"ts\">\n  import { useForm } from 'attaform\u002Fzod'\n  import { z } from 'zod'\n\n  const schema = z.object({\n    scoresByTeam: z.record(z.string(), z.number()),\n  })\n\n  const form = useForm({ schema })\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003Cdiv v-for=\"(field, key) in form.record('scoresByTeam')\" :key=\"key\">\n    \u003Clabel>{{ key }}\u003C\u002Flabel>\n    \u003Cinput v-register=\"form.register(`scoresByTeam.${key}`)\" \u002F>\n    \u003Cp v-if=\"field.showErrors\">{{ field.firstError?.message }}\u003C\u002Fp>\n  \u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n","vue","",[13,82,83,113,129,142,149,171,194,200,205,221,231,236,246,273,289,308,330,340],{"__ignoreMap":80},[84,85,88,92,96,100,103,106,110],"span",{"class":86,"line":87},"line",1,[84,89,91],{"class":90},"sVt8B","\u003C",[84,93,95],{"class":94},"s9eBZ","script",[84,97,99],{"class":98},"sScJk"," setup",[84,101,102],{"class":98}," lang",[84,104,105],{"class":90},"=",[84,107,109],{"class":108},"sZZnC","\"ts\"",[84,111,112],{"class":90},">\n",[84,114,116,120,123,126],{"class":86,"line":115},2,[84,117,119],{"class":118},"szBVR","  import",[84,121,122],{"class":90}," { useForm } ",[84,124,125],{"class":118},"from",[84,127,128],{"class":108}," 'attaform\u002Fzod'\n",[84,130,132,134,137,139],{"class":86,"line":131},3,[84,133,119],{"class":118},[84,135,136],{"class":90}," { z } ",[84,138,125],{"class":118},[84,140,141],{"class":108}," 'zod'\n",[84,143,145],{"class":86,"line":144},4,[84,146,148],{"emptyLinePlaceholder":147},true,"\n",[84,150,152,155,159,162,165,168],{"class":86,"line":151},5,[84,153,154],{"class":118},"  const",[84,156,158],{"class":157},"sj4cs"," schema",[84,160,161],{"class":118}," =",[84,163,164],{"class":90}," z.",[84,166,167],{"class":98},"object",[84,169,170],{"class":90},"({\n",[84,172,174,177,179,182,185,188,191],{"class":86,"line":173},6,[84,175,176],{"class":90},"    scoresByTeam: z.",[84,178,5],{"class":98},[84,180,181],{"class":90},"(z.",[84,183,184],{"class":98},"string",[84,186,187],{"class":90},"(), z.",[84,189,190],{"class":98},"number",[84,192,193],{"class":90},"()),\n",[84,195,197],{"class":86,"line":196},7,[84,198,199],{"class":90},"  })\n",[84,201,203],{"class":86,"line":202},8,[84,204,148],{"emptyLinePlaceholder":147},[84,206,208,210,213,215,218],{"class":86,"line":207},9,[84,209,154],{"class":118},[84,211,212],{"class":157}," form",[84,214,161],{"class":118},[84,216,217],{"class":98}," useForm",[84,219,220],{"class":90},"({ schema })\n",[84,222,224,227,229],{"class":86,"line":223},10,[84,225,226],{"class":90},"\u003C\u002F",[84,228,95],{"class":94},[84,230,112],{"class":90},[84,232,234],{"class":86,"line":233},11,[84,235,148],{"emptyLinePlaceholder":147},[84,237,239,241,244],{"class":86,"line":238},12,[84,240,91],{"class":90},[84,242,243],{"class":94},"template",[84,245,112],{"class":90},[84,247,249,252,255,258,260,263,266,268,271],{"class":86,"line":248},13,[84,250,251],{"class":90},"  \u003C",[84,253,254],{"class":94},"div",[84,256,257],{"class":98}," v-for",[84,259,105],{"class":90},[84,261,262],{"class":108},"\"(field, key) in form.record('scoresByTeam')\"",[84,264,265],{"class":98}," :key",[84,267,105],{"class":90},[84,269,270],{"class":108},"\"key\"",[84,272,112],{"class":90},[84,274,276,279,282,285,287],{"class":86,"line":275},14,[84,277,278],{"class":90},"    \u003C",[84,280,281],{"class":94},"label",[84,283,284],{"class":90},">{{ key }}\u003C\u002F",[84,286,281],{"class":94},[84,288,112],{"class":90},[84,290,292,294,297,300,302,305],{"class":86,"line":291},15,[84,293,278],{"class":90},[84,295,296],{"class":94},"input",[84,298,299],{"class":98}," v-register",[84,301,105],{"class":90},[84,303,304],{"class":108},"\"form.register(`scoresByTeam.${key}`)\"",[84,306,307],{"class":90}," \u002F>\n",[84,309,311,313,315,318,320,323,326,328],{"class":86,"line":310},16,[84,312,278],{"class":90},[84,314,19],{"class":94},[84,316,317],{"class":98}," v-if",[84,319,105],{"class":90},[84,321,322],{"class":108},"\"field.showErrors\"",[84,324,325],{"class":90},">{{ field.firstError?.message }}\u003C\u002F",[84,327,19],{"class":94},[84,329,112],{"class":90},[84,331,333,336,338],{"class":86,"line":332},17,[84,334,335],{"class":90},"  \u003C\u002F",[84,337,254],{"class":94},[84,339,112],{"class":90},[84,341,343,345,347],{"class":86,"line":342},18,[84,344,226],{"class":90},[84,346,243],{"class":94},[84,348,112],{"class":90},[19,350,351,353,354,357,358,361],{},[13,352,5],{}," is typed against every record path in the schema (a ",[13,355,356],{},"z.record(...)",", not a fixed-shape ",[13,359,360],{},"z.object({ ... })","), so the path autocompletes to records only, and each entry's type narrows to the record's value shape.",[63,363,365],{"id":364},"each-entry-is-a-live-fieldstate","Each entry is a live FieldState",[19,367,368,369,374,375,378,379,378,382,378,385,378,388,391,392,398],{},"Each value in the returned object is the same field state ",[40,370,371],{"href":52},[13,372,373],{},"fields"," exposes, so every read stays live as the user types. An entry carries the full surface: ",[13,376,377],{},"field.value",", ",[13,380,381],{},"field.errors",[13,383,384],{},"field.showErrors",[13,386,387],{},"field.firstError",[13,389,390],{},"field.touched",", and the rest. Binding still flows through ",[40,393,395],{"href":394},"\u002Fdocs\u002Fbinding-inputs\u002Fv-register",[13,396,397],{},"form.register"," with the entry path, which the key supplies.",[63,400,402],{"id":401},"growing-and-shrinking","Growing and shrinking",[19,404,405,406,412],{},"The returned object is frozen, a read-only view. A record carries its own keys, so you grow or shrink it through ",[40,407,409],{"href":408},"\u002Fdocs\u002Fwriting-and-mutating\u002Fset-value",[13,410,411],{},"setValue"," at an entry path. Write a key that isn't there yet and a new entry joins the view:",[75,414,418],{"className":415,"code":416,"language":417,"meta":80,"style":80},"language-ts shiki shiki-themes github-light github-dark","form.setValue('scoresByTeam.west', 0)\n","ts",[13,419,420],{"__ignoreMap":80},[84,421,422,425,427,430,433,435,438],{"class":86,"line":87},[84,423,424],{"class":90},"form.",[84,426,411],{"class":98},[84,428,429],{"class":90},"(",[84,431,432],{"class":108},"'scoresByTeam.west'",[84,434,378],{"class":90},[84,436,437],{"class":157},"0",[84,439,440],{"class":90},")\n",[19,442,443],{},"The existing entries keep their field states and their component instances; only the new row mounts. To drop an entry, write the record back without that key.",[63,445,447,450],{"id":446},"formfields-stays-the-aggregate",[13,448,449],{},"form.fields"," stays the aggregate",[19,452,453,456,457,378,460,463,464,467,468,470],{},[13,454,455],{},"form.fields('scoresByTeam')"," remains the single aggregated container for the whole record: one rolled-up FieldState whose ",[13,458,459],{},"errors",[13,461,462],{},"valid",", and ",[13,465,466],{},"touched"," summarize every entry at once. Reach for the aggregate when you want one verdict for the record, and for ",[13,469,5],{}," when you want an entry each.",[63,472,474,475],{"id":473},"the-root-record-formrecord","The root record, ",[13,476,477],{},"form.record()",[19,479,480,481,484,485,489,490,492],{},"When the schema root is itself a ",[13,482,483],{},"z.record"," (a ",[40,486,488],{"href":487},"\u002Fdocs\u002Fschemas\u002Fdictionary-forms","dictionary form","), call ",[13,491,477],{}," with no argument for the root entry view. It hands back the same keyed object of field states, one per entry, for the form's top-level map:",[75,494,496],{"className":77,"code":495,"language":79,"meta":80,"style":80},"\u003Ctemplate>\n  \u003Cdiv v-for=\"(member, id) in form.record()\" :key=\"id\">\n    \u003Cinput v-register=\"form.register(`${id}.tier`)\" type=\"number\" \u002F>\n  \u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n",[13,497,498,506,528,551,559],{"__ignoreMap":80},[84,499,500,502,504],{"class":86,"line":87},[84,501,91],{"class":90},[84,503,243],{"class":94},[84,505,112],{"class":90},[84,507,508,510,512,514,516,519,521,523,526],{"class":86,"line":115},[84,509,251],{"class":90},[84,511,254],{"class":94},[84,513,257],{"class":98},[84,515,105],{"class":90},[84,517,518],{"class":108},"\"(member, id) in form.record()\"",[84,520,265],{"class":98},[84,522,105],{"class":90},[84,524,525],{"class":108},"\"id\"",[84,527,112],{"class":90},[84,529,530,532,534,536,538,541,544,546,549],{"class":86,"line":131},[84,531,278],{"class":90},[84,533,296],{"class":94},[84,535,299],{"class":98},[84,537,105],{"class":90},[84,539,540],{"class":108},"\"form.register(`${id}.tier`)\"",[84,542,543],{"class":98}," type",[84,545,105],{"class":90},[84,547,548],{"class":108},"\"number\"",[84,550,307],{"class":90},[84,552,553,555,557],{"class":86,"line":144},[84,554,335],{"class":90},[84,556,254],{"class":94},[84,558,112],{"class":90},[84,560,561,563,565],{"class":86,"line":151},[84,562,226],{"class":90},[84,564,243],{"class":94},[84,566,112],{"class":90},[19,568,569,570,573],{},"The no-argument form is available only on a record root; on a fixed-shape object root it is a compile error, the same way the path form requires a record path. See ",[40,571,572],{"href":487},"Dictionary forms"," for the whole-form story.",[63,575,577,579],{"id":576},"list-is-the-array-counterpart",[13,578,45],{}," is the array counterpart",[19,581,582,583,587,588,590,591,593,594,596,597,599],{},"For an array, reach for ",[40,584,585],{"href":42},[13,586,45],{},", which returns an ordered FieldState array keyed by an allocated identity token that survives reorders. ",[13,589,5],{}," and ",[13,592,45],{}," split cleanly by path type: a record reads through ",[13,595,5],{},", an array through ",[13,598,45],{},", and each rejects the other at compile time.",[63,601,603],{"id":602},"where-to-next","Where to next",[605,606,607,615,625,635,642],"ul",{},[608,609,610,614],"li",{},[40,611,612],{"href":42},[13,613,45],{},": the array counterpart, one FieldState per element with reorder-stable keys.",[608,616,617,619,620,622,623,29],{},[40,618,572],{"href":487},": a ",[13,621,483],{}," schema as the form root, iterated with the no-argument ",[13,624,477],{},[608,626,627,631,632,634],{},[40,628,630],{"href":629},"\u002Fdocs\u002Fschemas\u002Frecords","Records & maps",": declaring a ",[13,633,356],{}," schema and binding its entries.",[608,636,637,641],{},[40,638,639],{"href":52},[13,640,373],{},": the per-leaf FieldState every entry carries.",[608,643,644,648],{},[40,645,646],{"href":408},[13,647,411],{},": how an entry joins or leaves the record.",[650,651,652],"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 pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}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);}",{"title":80,"searchDepth":115,"depth":115,"links":654},[655,656,657,658,660,662,664],{"id":65,"depth":115,"text":66},{"id":364,"depth":115,"text":365},{"id":401,"depth":115,"text":402},{"id":446,"depth":115,"text":659},"form.fields stays the aggregate",{"id":473,"depth":115,"text":661},"The root record, form.record()",{"id":576,"depth":115,"text":663},"list is the array counterpart",{"id":602,"depth":115,"text":603},"form.record reads a record as one FieldState per entry, keyed by the entry's own key, so you iterate dynamic keys without tracking them yourself.","md",{},[669,672,675],{"label":670,"value":671},"Category","Return method",{"label":673,"value":674,"kind":13},"Type","(path?) => Readonly\u003CRecord\u003Cstring, FieldState>>",{"label":676,"value":677},"Keyed","Yes, by record key","\u002Fdocs\u002Freading-the-form\u002Frecord",{"title":5,"description":665},null,"docs\u002Freading-the-form\u002Frecord","MVFIDv1xdPJ3iyimSXcovoFPj2ncHvOVOt-FUt2RCyQ",1781745871737]