[{"data":1,"prerenderedAt":1468},["ShallowReactive",2],{"navigation":3,"search":85,"$f12k3lmnboe3wd":1059,"i-custom:logo":1060,"i-tabler:search":1064,"i-tabler:moon":1066,"i-tabler:sun":1068,"i-simple-icons:github":1070,"i-tabler:heart":1072,"i-tabler:menu":1074,"i-tabler:rocket":1076,"i-tabler:package":1078,"i-tabler:bolt":1080,"i-simple-icons:nuxtdotjs":1082,"i-tabler:robot":1084,"i-tabler:code":1086,"i-tabler:function":1088,"i-tabler:chevron-down":1090,"i-tabler:settings":1092,"i-tabler:server":1094,"i-tabler:shield-lock":1096,"\u002Fgetting-started\u002Finstallation":1098,"\u002Fgetting-started\u002Finstallation-surround":1440,"i-tabler:copy":1445,"i-tabler:edit":1447,"i-tabler:star":1449,"i-tabler:external-link":1451,"i-tabler:info-square-rounded":1453,"i-tabler:hash":1455,"i-vscode-icons:file-type-pnpm":1457,"i-vscode-icons:file-type-yarn":1460,"i-vscode-icons:file-type-npm":1462,"i-vscode-icons:file-type-bun":1464,"i-vscode-icons:file-type-vue":1466},[4,33,55,65],{"title":5,"path":6,"stem":7,"children":8,"icon":32},"Getting Started","\u002Fgetting-started","1.getting-started\u002F1.index",[9,12,17,22,27],{"title":10,"path":6,"stem":7,"icon":11},"Introduction","tabler:rocket",{"title":13,"path":14,"stem":15,"icon":16},"Installation","\u002Fgetting-started\u002Finstallation","1.getting-started\u002F2.installation","tabler:package",{"title":18,"path":19,"stem":20,"icon":21},"Quickstart","\u002Fgetting-started\u002Fquickstart","1.getting-started\u002F3.quickstart","tabler:bolt",{"title":23,"path":24,"stem":25,"icon":26},"Nuxt Module","\u002Fgetting-started\u002Fnuxt-module","1.getting-started\u002F4.nuxt-module","simple-icons:nuxtdotjs",{"title":28,"path":29,"stem":30,"icon":31},"AI Models","\u002Fgetting-started\u002Fai-models","1.getting-started\u002F5.ai-models","tabler:robot",false,{"title":34,"icon":32,"path":35,"stem":36,"children":37,"page":32},"Components","\u002Fcomponents","2.components",[38,43,47,51],{"title":39,"path":40,"stem":41,"icon":42},"NotForm","\u002Fcomponents\u002Fnot-form","2.components\u002F1.not-form","tabler:code",{"title":44,"path":45,"stem":46,"icon":42},"NotField","\u002Fcomponents\u002Fnot-field","2.components\u002F2.not-field",{"title":48,"path":49,"stem":50,"icon":42},"NotMessage","\u002Fcomponents\u002Fnot-message","2.components\u002F3.not-message",{"title":52,"path":53,"stem":54,"icon":42},"NotArrayField","\u002Fcomponents\u002Fnot-array-field","2.components\u002F4.not-array-field",{"title":56,"icon":32,"path":57,"stem":58,"children":59,"page":32},"Composables","\u002Fcomposables","3.composables",[60],{"title":61,"path":62,"stem":63,"icon":64},"useNotForm","\u002Fcomposables\u002Fuse-not-form","3.composables\u002F1.use-not-form","tabler:function",{"title":66,"icon":32,"path":67,"stem":68,"children":69,"page":32},"Advanced","\u002Fadvanced","4.advanced",[70,75,80],{"title":71,"path":72,"stem":73,"icon":74},"Validation Modes","\u002Fadvanced\u002Fvalidation-modes","4.advanced\u002F1.validation-modes","tabler:settings",{"title":76,"path":77,"stem":78,"icon":79},"Server Errors","\u002Fadvanced\u002Fserver-errors","4.advanced\u002F2.server-errors","tabler:server",{"title":81,"path":82,"stem":83,"icon":84},"Schema Validation","\u002Fadvanced\u002Fschema-validation","4.advanced\u002F3.schema-validation","tabler:shield-lock",[86,90,96,101,104,109,114,119,123,126,131,136,141,144,148,153,158,164,169,174,177,182,187,192,195,200,205,210,215,220,223,227,232,237,242,247,252,256,261,266,271,276,281,286,291,295,300,305,309,314,319,324,329,332,336,340,345,349,353,357,362,367,371,376,381,386,391,394,398,402,407,411,415,419,424,427,431,436,441,446,451,456,461,466,471,476,481,485,489,493,497,502,507,510,515,520,525,530,535,539,544,550,555,560,565,569,573,577,581,585,589,593,598,603,607,612,616,621,625,630,634,639,643,647,652,657,662,667,672,676,680,685,690,694,698,702,707,712,716,721,726,731,736,741,744,749,753,757,762,767,770,775,780,785,790,795,800,805,810,815,819,824,829,834,839,843,848,853,858,861,866,871,876,881,886,891,896,901,906,911,916,921,925,930,935,940,945,948,953,956,961,966,971,976,981,986,991,996,1000,1005,1010,1015,1020,1025,1029,1034,1039,1044,1049,1054],{"id":6,"title":10,"titles":87,"content":88,"level":89},[],"Headless, schema-agnostic form management for Vue 3 and Nuxt. NotForm is a powerful, lightweight form state and validation library built specifically for the Vue 3 Composition API. It handles validation state, dirty\u002Ftouched tracking, per-field triggers, and complex array manipulations. However, NotForm renders absolutely nothing. It provides the state, and you provide the UI.",1,{"id":91,"title":92,"titles":93,"content":94,"level":95},"\u002Fgetting-started#why-notform","Why NotForm?",[10],"Building forms in Vue often involves choosing between a massive UI library that dictates your design, or a complex validation library that requires endless boilerplate. NotForm bridges this gap. It works flawlessly with any Standard Schema compliant validator (like Zod, Valibot, or ArkType) and lets you bring your own components—whether they are native HTML elements, Nuxt UI, or Shadcn Vue. Full-form and per-field validation with async support. Trigger validations on blur, input, change, focus, or component mount.Fields are compared against initial values on every keystroke. Touched and dirty states are managed automatically.Append, prepend, insert, remove, swap, and move array items with stable keys that survive reorders.Field paths and their value types are strictly inferred from your schema. Invalid paths trigger compile-time errors.",2,{"id":97,"title":98,"titles":99,"content":100,"level":95},"\u002Fgetting-started#next-steps","Next steps",[10],"Ready to dive in? Check out the Installation guide to add NotForm to your project.",{"id":14,"title":13,"titles":102,"content":103,"level":89},[],"Add NotForm to your Vue 3 or Vite project. NotForm is distributed as an npm package and can be used directly in any Vue 3 application. If you are using Nuxt, we recommend using the official Nuxt Module instead. The Nuxt integration handles the framework-specific setup for you and provides a zero-config experience.",{"id":105,"title":106,"titles":107,"content":108,"level":95},"\u002Fgetting-started\u002Finstallation#install-the-package","Install the package",[13],"Install NotForm using your preferred package manager. NotForm uses Standard Schema for validation, so you will also need a compatible validation library. Popular options include Zod, Valibot, and ArkType. Choose the validation library you want to use and install it alongside NotForm. pnpm add notform zod\nyarn add notform zod\nnpm install notform zod\nbun add notform zod You can replace zod with another Standard Schema-compatible validation library if you prefer.",{"id":110,"title":111,"titles":112,"content":113,"level":95},"\u002Fgetting-started\u002Finstallation#vue-and-vite","Vue and Vite",[13],"NotForm is designed for Vue 3 and works with standard Vue applications without requiring a special build step or application-level configuration. Once installed, you can import the components, composables, and utilities you need directly from notform: \u003Cscript setup lang=\"ts\">\nimport { NotField, NotForm, NotMessage } from 'notform'\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003CNotForm>\n    \u003C!-- form fields -->\n  \u003C\u002FNotForm>\n\u003C\u002Ftemplate> NotForm follows the normal Vue component model, so there is no global registration step required. Import only the pieces you use in your application. The exact form structure and available components are covered in the Quickstart.",{"id":115,"title":116,"titles":117,"content":118,"level":95},"\u002Fgetting-started\u002Finstallation#nuxt","Nuxt",[13],"For Nuxt applications, use the Nuxt Module rather than manually configuring NotForm. The module integrates NotForm with Nuxt and takes care of the framework-specific setup, allowing you to start using NotForm without adding that configuration yourself.",{"id":120,"title":98,"titles":121,"content":122,"level":95},"\u002Fgetting-started\u002Finstallation#next-steps",[13],"NotForm is now ready to use in your project. Continue to the Quickstart to create your first form and learn how NotForm's components, fields, validation, and Standard Schema integration work together. html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}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 .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}",{"id":19,"title":18,"titles":124,"content":125,"level":89},[],"Build a fully typed login form with validation in minutes. This guide walks you through building a simple login form using the useNotForm composable and NotForm's headless components.",{"id":127,"title":128,"titles":129,"content":130,"level":95},"\u002Fgetting-started\u002Fquickstart#demo","Demo",[18],"Here is the login form we will be building. Try submitting the form empty, or typing an invalid email to see the validation in action.",{"id":132,"title":133,"titles":134,"content":135,"level":95},"\u002Fgetting-started\u002Fquickstart#step-by-step","Step-by-step",[18],"Define the SchemaFirst, define your validation schema using a Standard Schema compliant library (we use zod in this example). This acts as the single source of truth for both your form's data shape and its validation rules.import { z } from 'zod'\n\nconst schema = z.object({\n  email: z.email('Enter a valid email'),\n  password: z.string('Invalid input').min(8, 'At least 8 characters'),\n})\nInitialize the FormUse the useNotForm composable to create your form instance. Pass in the schema and define an onSubmit handler.const form = useNotForm({\n  async onSubmit(data) {\n    \u002F\u002F `data` is fully typed as { email: string, password: string }\n    console.log('Form submitted:', data)\n  },\n  schema,\n})\nRender the FormUse the \u003CNotForm> component to wrap your form. It automatically handles the native submit and reset events, preventing default browser behavior.\u003Ctemplate>\n  \u003CNotForm\n    :form=\"form\"\n    @submit=\"form.submit\"\n    @reset=\"form.reset()\"\n  >\n    \u003C!-- Fields will go here -->\n\n    \u003Cbutton\n      type=\"submit\"\n      :disabled=\"form.isSubmitting.value\"\n    >\n      Submit\n    \u003C\u002Fbutton>\n  \u003C\u002FNotForm>\n\u003C\u002Ftemplate>\nConnect the FieldsUse the \u003CNotField> component for each field. It exposes an events object that you bind to your native \u003Cinput> (which sets up blur and input listeners), and the path which serves as a stable ID.\u003CNotField v-slot=\"{ events, path }\" path=\"email\">\n  \u003Cdiv>\n    \u003Clabel :for=\"path\">Email\u003C\u002Flabel>\n    \u003Cinput\n      :id=\"path\"\n      v-model=\"form.values.email\"\n      v-bind=\"events\"\n      type=\"email\"\n    \u002F>\n    \u003CNotMessage :path=\"path\" \u002F>\n  \u003C\u002Fdiv>\n\u003C\u002FNotField>\nThe \u003CNotMessage> component automatically displays the first validation error for the given path. If there are no errors, it renders nothing.",{"id":137,"title":138,"titles":139,"content":140,"level":95},"\u002Fgetting-started\u002Fquickstart#next-steps","Next Steps",[18],"You now have a fully typed, validating form! To learn more about how NotForm integrates into your Vue applications, check out the Components guide, or deep dive into Composables. html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}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 .sHdIc, html code.shiki .sHdIc{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#EEFFFF;--shiki-default-font-style:italic;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}",{"id":24,"title":23,"titles":142,"content":143,"level":89},[],"Seamless integration with Nuxt 4, featuring auto-imports and zero configuration. The official notform-nuxt module provides a first-class developer experience for using NotForm in Nuxt applications. It handles component and composable registration automatically.",{"id":145,"title":13,"titles":146,"content":147,"level":95},"\u002Fgetting-started\u002Fnuxt-module#installation",[23],"The module is registered in the official Nuxt Modules Registry, meaning you can easily install it using the Nuxt CLI. npx nuxi module add notform\npnpm dlx nuxi module add notform\nbunx nuxi module add notform\nyarn dlx nuxi module add notform This command will automatically install notform-nuxt and add it to the modules array in your nuxt.config.ts. You still need to install your preferred validation library (e.g., zod). pnpm add zod",{"id":149,"title":150,"titles":151,"content":152,"level":95},"\u002Fgetting-started\u002Fnuxt-module#manual-setup","Manual Setup",[23],"If you prefer to install manually, add the dependency: pnpm add notform-nuxt Then, add it to your nuxt.config.ts: export default defineNuxtConfig({\n  modules: ['notform-nuxt'],\n})",{"id":154,"title":155,"titles":156,"content":157,"level":95},"\u002Fgetting-started\u002Fnuxt-module#features","Features",[23],"",{"id":159,"title":160,"titles":161,"content":162,"level":163},"\u002Fgetting-started\u002Fnuxt-module#auto-imports","Auto-imports",[23,155],"All core components and composables are available globally in your Vue files without any manual imports. ExportTypeDescriptionuseNotFormComposableThe core form management composable.NotFormComponentContext provider and \u003Cform> wrapper.NotFieldComponentRenderless wrapper for single fields.NotMessageComponentError message renderer.NotArrayFieldComponentRenderless wrapper for dynamic array fields.",3,{"id":165,"title":166,"titles":167,"content":168,"level":163},"\u002Fgetting-started\u002Fnuxt-module#type-safety","Type Safety",[23,155],"Types for NotFormInstance, UseNotFormConfig, and NotFieldProps are automatically injected into your project's global types for perfect IntelliSense.",{"id":170,"title":171,"titles":172,"content":173,"level":163},"\u002Fgetting-started\u002Fnuxt-module#server-side-rendering-ssr","Server-side Rendering (SSR)",[23,155],"NotForm is fully compatible with Nuxt's SSR engine. Form state and validation rules are safely executed on the server during the initial render without hydration mismatches. html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}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 .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}",{"id":29,"title":28,"titles":175,"content":176,"level":89},[],"How to feed NotForm documentation to LLMs and AI coding assistants. We've made sure NotForm is as easy for Artificial Intelligence to understand as it is for humans. This documentation site is built with nuxt-llms, which automatically generates optimized, plain-text versions of the documentation specifically designed for Large Language Models (LLMs) and AI coding assistants (like Cursor, Copilot, or Claude).",{"id":178,"title":179,"titles":180,"content":181,"level":95},"\u002Fgetting-started\u002Fai-models#usage","Usage",[28],"When asking an AI assistant to build a form using NotForm, you can instruct it to read our LLM-optimized documentation file: https:\u002F\u002Fnotformdocs.vercel.app\u002Fllms.txt",{"id":183,"title":184,"titles":185,"content":186,"level":163},"\u002Fgetting-started\u002Fai-models#full-documentation","Full Documentation",[28,179],"If the AI needs deep context on every API, component, and advanced feature, provide it with the full documentation text file: https:\u002F\u002Fnotformdocs.vercel.app\u002Fllms-full.txt",{"id":188,"title":189,"titles":190,"content":191,"level":163},"\u002Fgetting-started\u002Fai-models#example-prompt","Example Prompt",[28,179],"You can use a prompt like this in your AI editor: \"I need to build a user settings form with a dynamic array of email addresses. Please read the documentation at https:\u002F\u002Fnotformdocs.vercel.app\u002Fllms.txt to understand how to use NotForm's \u003CNotArrayField> and useNotForm API before writing the Vue component.\" By providing this URL, the AI will perfectly understand NotForm's headless philosophy, validation modes, and type-safe schema integration.",{"id":40,"title":39,"titles":193,"content":194,"level":89},[],"The root form component that provides context and handles submit\u002Freset events. \u003CNotForm> is the root component that wraps your form. It provides the form context to all child components and handles the native submit and reset events.",{"id":196,"title":197,"titles":198,"content":199,"level":95},"\u002Fcomponents\u002Fnot-form#props","Props",[39],"PropTypeRequiredDescriptionformNotFormInstance\u003CTSchema>YesThe form instance returned from useNotForm",{"id":201,"title":202,"titles":203,"content":204,"level":95},"\u002Fcomponents\u002Fnot-form#events","Events",[39],"EventPayloadDescriptionsubmitSubmitEventFired when the form is submitted. Call form.submit() to trigger validation and submission.resetEventFired when the form is reset. Call form.reset() to reset the form to initial values.",{"id":206,"title":207,"titles":208,"content":209,"level":95},"\u002Fcomponents\u002Fnot-form#basic-usage","Basic Usage",[39],"\u003Cscript setup lang=\"ts\">\nimport { z } from 'zod'\n\nconst schema = z.object({\n  email: z.email('Invalid email'),\n  password: z.string().min(8, 'Password must be at least 8 characters'),\n})\n\nconst form = useNotForm({\n  onSubmit(values) {\n    console.log('Form submitted:', values)\n  },\n  schema,\n})\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003CNotForm\n    :form=\"form\"\n    @submit=\"form.submit\"\n    @reset=\"form.reset()\"\n  >\n    \u003C!-- Form fields go here -->\n    \u003Cbutton type=\"submit\">\n      Submit\n    \u003C\u002Fbutton>\n\n    \u003Cbutton type=\"reset\">\n      Reset\n    \u003C\u002Fbutton>\n  \u003C\u002FNotForm>\n\u003C\u002Ftemplate>",{"id":211,"title":212,"titles":213,"content":214,"level":95},"\u002Fcomponents\u002Fnot-form#how-it-works","How It Works",[39],"\u003CNotForm> automatically: Prevents the default browser form submission behaviorProvides the form context to all child \u003CNotField> and \u003CNotArrayField> componentsHandles form reset to clear validation errors and restore initial values",{"id":216,"title":217,"titles":218,"content":219,"level":95},"\u002Fcomponents\u002Fnot-form#native-form-element","Native Form Element",[39],"Under the hood, \u003CNotForm> renders a native \u003Cform> element, which means: You can use native form attributes like action, method, enctypeForm submission works with keyboard (Enter key) and accessibility toolsThe form integrates naturally with browser validation if needed html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html pre.shiki code .sHdIc, html code.shiki .sHdIc{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#EEFFFF;--shiki-default-font-style:italic;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}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);}",{"id":45,"title":44,"titles":221,"content":222,"level":89},[],"Renderless component for individual form fields with validation state and event handlers. \u003CNotField> is a renderless component that connects an individual field to NotForm's validation and state management. It provides the field's current state, validation errors, a validation method, and event handlers that can be bound to native inputs or custom form components.",{"id":224,"title":197,"titles":225,"content":226,"level":95},"\u002Fcomponents\u002Fnot-field#props",[44],"PropTypeRequiredDescriptionpathstringYesDot-separated path to the field within the form values.formNotFormInstance\u003Cany>NoExplicit form instance to use. Takes priority over a NotForm ancestor and is required when using NotField outside a NotForm.validateOnPartial\u003CRecord\u003CValidationTrigger, boolean>>NoOverrides individual form-wide validation triggers for this field.debouncenumberNoDelays input- and change-triggered validation by the specified number of milliseconds.",{"id":228,"title":229,"titles":230,"content":231,"level":163},"\u002Fcomponents\u002Fnot-field#path","path",[44,197],"The field path identifies the value managed by the field. Simple fields use a single property name: \u003CNotField path=\"email\">\n  ...\n\u003C\u002FNotField> Nested fields use dot notation: \u003CNotField path=\"user.email\">\n  ...\n\u003C\u002FNotField> The same path is exposed through the default slot and can be used for labels, IDs, messages, and other field-specific elements.",{"id":233,"title":234,"titles":235,"content":236,"level":163},"\u002Fcomponents\u002Fnot-field#form","form",[44,197],"By default, NotField uses the form instance provided by a surrounding NotForm. You can explicitly provide a form instance when needed: \u003CNotField :form=\"form\" path=\"email\" v-slot=\"{ events }\">\n  \u003Cinput v-bind=\"events\" \u002F>\n\u003C\u002FNotField> An explicit form takes priority over the form provided by a NotForm ancestor. This is also required when using NotField as a standalone field outside of a NotForm.",{"id":238,"title":239,"titles":240,"content":241,"level":163},"\u002Fcomponents\u002Fnot-field#validateon","validateOn",[44,197],"validateOn allows individual validation triggers to be overridden for a field. Only the triggers you specify are overridden; all other form-wide settings remain unchanged. \u003CNotField\n  path=\"username\"\n  :validate-on=\"{ onInput: true }\"\n\u002F> For example, if the form validates on blur, the field above will additionally validate on input.",{"id":243,"title":244,"titles":245,"content":246,"level":163},"\u002Fcomponents\u002Fnot-field#debounce","debounce",[44,197],"debounce delays input- and change-triggered validation until the user stops interacting with the field for the specified number of milliseconds. This is particularly useful for asynchronous validation where validating on every keystroke could result in excessive requests. \u003CNotField\n  path=\"username\"\n  :debounce=\"400\"\n  v-slot=\"{ events }\"\n>\n  \u003Cinput\n    v-model=\"form.values.username\"\n    v-bind=\"events\"\n  \u002F>\n\u003C\u002FNotField> Blur and submit-triggered validation is not delayed by debounce. Omit the prop or set it to 0 to disable debouncing.",{"id":248,"title":249,"titles":250,"content":251,"level":95},"\u002Fcomponents\u002Fnot-field#slot-props","Slot Props",[44],"The default slot receives the complete field state and event handlers. \u003CNotField v-slot=\"field\" path=\"email\">\n  ...\n\u003C\u002FNotField> PropTypeDescriptionpathstringThe dot-separated path of the field.valueanyThe current field value as a read-only snapshot.errorsStandardSchemaV1.Issue[]Validation issues from the last validation run.isValidbooleanWhether the field currently has no validation errors.isTouchedbooleanWhether the field has been interacted with or the form has been submitted.isDirtybooleanWhether the current value differs from the initial value.isValidatingbooleanWhether asynchronous validation is currently running for the field.validate() => ReturnType\u003CNotFormInstance\u003CTSchema>['validateField']>Manually triggers validation for the field.eventsonBlur: () => void  onInput: () => void  onChange: () => void  onFocus: () => voidEvent handlers used to connect the field to NotForm.",{"id":253,"title":229,"titles":254,"content":255,"level":163},"\u002Fcomponents\u002Fnot-field#path-1",[44,249],"The field's path is available directly from the slot: \u003CNotField v-slot=\"{ path }\" path=\"email\">\n  \u003Clabel :for=\"path\">Email\u003C\u002Flabel>\n\u003C\u002FNotField>",{"id":257,"title":258,"titles":259,"content":260,"level":163},"\u002Fcomponents\u002Fnot-field#value","value",[44,249],"value contains the current value of the field. It is intended as a read-only snapshot for displaying or inspecting the current value. \u003CNotField v-slot=\"{ value }\" path=\"email\">\n  \u003Cp>Current value: {{ value }}\u003C\u002Fp>\n\u003C\u002FNotField> Do not mutate value directly or use it as the source for v-model. For two-way binding, bind your input to the form's values instead: \u003Cinput v-model=\"form.values.email\" \u002F>",{"id":262,"title":263,"titles":264,"content":265,"level":163},"\u002Fcomponents\u002Fnot-field#errors","errors",[44,249],"errors contains all validation issues reported for the field during the most recent validation run. \u003CNotField v-slot=\"{ errors }\" path=\"email\">\n  \u003Cinput v-model=\"form.values.email\" \u002F>\n\n  \u003Cul v-if=\"errors.length\">\n    \u003Cli v-for=\"error in errors\" :key=\"error.message\">\n      {{ error.message }}\n    \u003C\u002Fli>\n  \u003C\u002Ful>\n\u003C\u002FNotField> Each error is a StandardSchemaV1.Issue.",{"id":267,"title":268,"titles":269,"content":270,"level":163},"\u002Fcomponents\u002Fnot-field#isvalid","isValid",[44,249],"isValid indicates whether the field currently has no validation errors. \u003CNotField v-slot=\"{ isValid }\" path=\"email\">\n  \u003Cspan v-if=\"isValid\">Valid\u003C\u002Fspan>\n\u003C\u002FNotField>",{"id":272,"title":273,"titles":274,"content":275,"level":163},"\u002Fcomponents\u002Fnot-field#istouched","isTouched",[44,249],"isTouched indicates whether the field has been interacted with or the form has been submitted. This can be useful for displaying validation feedback only after the user has interacted with the field: \u003CNotField\n  v-slot=\"{ isTouched, isValid, events }\"\n  path=\"email\"\n>\n  \u003Cinput\n    v-model=\"form.values.email\"\n    v-bind=\"events\"\n  \u002F>\n\n  \u003Cp v-if=\"isTouched && !isValid\">\n    Please enter a valid email address.\n  \u003C\u002Fp>\n\u003C\u002FNotField>",{"id":277,"title":278,"titles":279,"content":280,"level":163},"\u002Fcomponents\u002Fnot-field#isdirty","isDirty",[44,249],"isDirty indicates whether the field's current value differs from its initial value. \u003CNotField v-slot=\"{ isDirty }\" path=\"email\">\n  \u003Cspan v-if=\"isDirty\">Unsaved changes\u003C\u002Fspan>\n\u003C\u002FNotField>",{"id":282,"title":283,"titles":284,"content":285,"level":163},"\u002Fcomponents\u002Fnot-field#isvalidating","isValidating",[44,249],"isValidating is true while asynchronous validation is running for the field. \u003CNotField v-slot=\"{ isValidating }\" path=\"username\">\n  \u003Cspan v-if=\"isValidating\">\n    Checking username...\n  \u003C\u002Fspan>\n\u003C\u002FNotField> This is particularly useful for fields that use asynchronous validators.",{"id":287,"title":288,"titles":289,"content":290,"level":163},"\u002Fcomponents\u002Fnot-field#validate","validate",[44,249],"validate manually triggers validation for the field. This is useful for custom inputs that manage their own interaction events or when validation needs to be triggered programmatically from the field's UI. \u003CNotField v-slot=\"{ validate }\" path=\"email\">\n  \u003Cbutton type=\"button\" @click=\"validate\">\n    Validate email\n  \u003C\u002Fbutton>\n\u003C\u002FNotField>",{"id":292,"title":202,"titles":293,"content":294,"level":95},"\u002Fcomponents\u002Fnot-field#events",[44],"The events slot prop contains the event handlers NotForm uses to track field interaction and trigger validation. \u003CNotField v-slot=\"{ events }\" path=\"email\">\n  \u003Cinput v-bind=\"events\" \u002F>\n\u003C\u002FNotField> The event object contains: {\n  onBlur: () => void,\n  onInput: () => void\n  onChange: () => void\n  onFocus: () => void\n}",{"id":296,"title":297,"titles":298,"content":299,"level":163},"\u002Fcomponents\u002Fnot-field#binding-all-events","Binding all events",[44,202],"For native inputs, the simplest approach is to spread the handlers: \u003CNotField v-slot=\"{ events }\" path=\"email\">\n  \u003Cinput\n    v-model=\"form.values.email\"\n    v-bind=\"events\"\n    type=\"email\"\n  \u002F>\n\u003C\u002FNotField> NotForm can then use the configured validation triggers and track the field's interaction state.",{"id":301,"title":302,"titles":303,"content":304,"level":163},"\u002Fcomponents\u002Fnot-field#binding-individual-events","Binding individual events",[44,202],"For custom components, bind the relevant handlers individually: \u003CNotField v-slot=\"{ events }\" path=\"country\">\n  \u003CCustomCombobox\n    v-on:focusout=\"events.onBlur\"\n    v-on:pick=\"events.onChange\"\n  \u002F>\n\u003C\u002FNotField> The handlers don't require the original DOM event as an argument. They simply notify NotField that the corresponding interaction occurred.",{"id":306,"title":207,"titles":307,"content":308,"level":95},"\u002Fcomponents\u002Fnot-field#basic-usage",[44],"A typical field combines the slot props with a form input and NotMessage: \u003CNotField v-slot=\"{ events, path }\" path=\"email\">\n  \u003Clabel :for=\"path\">Email\u003C\u002Flabel>\n\n  \u003Cinput\n    :id=\"path\"\n    v-model=\"form.values.email\"\n    v-bind=\"events\"\n    type=\"email\"\n  \u002F>\n\n  \u003CNotMessage :path=\"path\" \u002F>\n\u003C\u002FNotField>",{"id":310,"title":311,"titles":312,"content":313,"level":95},"\u002Fcomponents\u002Fnot-field#nested-fields","Nested Fields",[44],"NotField supports nested object paths using dot notation. Given a schema such as: const schema = z.object({\n  user: z.object({\n    email: z.email(),\n    name: z.string(),\n  }),\n}) You can address nested fields directly: \u003CNotField v-slot=\"{ events, path }\" path=\"user.name\">\n  \u003Clabel :for=\"path\">Name\u003C\u002Flabel>\n\n  \u003Cinput\n    :id=\"path\"\n    v-model=\"form.values.user.name\"\n    v-bind=\"events\"\n  \u002F>\n\n  \u003CNotMessage :path=\"path\" \u002F>\n\u003C\u002FNotField>\n\n\u003CNotField v-slot=\"{ events, path }\" path=\"user.email\">\n  \u003Clabel :for=\"path\">Email\u003C\u002Flabel>\n\n  \u003Cinput\n    :id=\"path\"\n    v-model=\"form.values.user.email\"\n    v-bind=\"events\"\n  \u002F>\n\n  \u003CNotMessage :path=\"path\" \u002F>\n\u003C\u002FNotField>",{"id":315,"title":316,"titles":317,"content":318,"level":95},"\u002Fcomponents\u002Fnot-field#per-field-validation","Per-Field Validation",[44],"Use validateOn when a field needs different validation behavior from the rest of the form. For example, a form might normally validate on blur while a username field also validates while the user types: \u003CNotField\n  path=\"username\"\n  :validate-on=\"{ onInput: true }\"\n  v-slot=\"{ events }\"\n>\n  \u003Cinput\n    v-model=\"form.values.username\"\n    v-bind=\"events\"\n  \u002F>\n\u003C\u002FNotField> Because validateOn is partial, unspecified triggers continue to use the form-wide configuration.",{"id":320,"title":321,"titles":322,"content":323,"level":95},"\u002Fcomponents\u002Fnot-field#debounced-validation","Debounced Validation",[44],"For fields with expensive or asynchronous validation, combine validateOn with debounce: \u003CNotField\n  path=\"username\"\n  :validate-on=\"{ onInput: true }\"\n  :debounce=\"400\"\n  v-slot=\"{ events, isValidating, errors }\"\n>\n  \u003Cinput\n    v-model=\"form.values.username\"\n    v-bind=\"events\"\n  \u002F>\n\n  \u003Cspan v-if=\"isValidating\">\n    Checking...\n  \u003C\u002Fspan>\n\n  \u003Cp v-for=\"error in errors\" :key=\"error.message\">\n    {{ error.message }}\n  \u003C\u002Fp>\n\u003C\u002FNotField> Validation waits until the user stops typing for 400ms before running. This helps prevent unnecessary validation calls while the user is entering a value.",{"id":325,"title":326,"titles":327,"content":328,"level":95},"\u002Fcomponents\u002Fnot-field#standalone-fields","Standalone Fields",[44],"NotField can be used outside a NotForm by providing a form instance explicitly: \u003CNotField\n  :form=\"form\"\n  path=\"email\"\n  v-slot=\"{ events }\"\n>\n  \u003Cinput\n    v-model=\"form.values.email\"\n    v-bind=\"events\"\n    type=\"email\"\n  \u002F>\n\u003C\u002FNotField> The explicit form instance takes priority over any form provided through a NotForm ancestor. html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}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 .sfNiH, html code.shiki .sfNiH{--shiki-light:#FF5370;--shiki-default:#FF9CAC;--shiki-dark:#FF9CAC}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}",{"id":49,"title":48,"titles":330,"content":331,"level":89},[],"Component for displaying validation errors for a specific field. \u003CNotMessage> is a small component for displaying the validation error message for a specific field. It automatically displays the first active validation error for the field and renders nothing when the field has no validation errors.",{"id":333,"title":197,"titles":334,"content":335,"level":95},"\u002Fcomponents\u002Fnot-message#props",[48],"PropTypeRequiredDefaultDescriptionpathstringYes—Dot-separated path of the field whose error should be displayed.asComponent | stringNospanHTML tag or Vue component used to render the message.formNotFormInstance\u003Cany>No—Explicit form instance to use. Takes priority over a NotForm ancestor.",{"id":337,"title":229,"titles":338,"content":339,"level":163},"\u002Fcomponents\u002Fnot-message#path",[48,197],"path identifies the field whose validation error should be displayed. It supports the same dot-separated paths used by NotField: \u003CNotMessage path=\"email\" \u002F> For nested fields: \u003CNotMessage path=\"user.email\" \u002F>",{"id":341,"title":342,"titles":343,"content":344,"level":163},"\u002Fcomponents\u002Fnot-message#as","as",[48,197],"By default, the error message is rendered as a \u003Cspan>. Use as to change the rendered element or provide a Vue component: \u003CNotMessage\n  path=\"email\"\n  as=\"p\"\n\u002F> You can also provide a component: \u003CNotMessage\n  path=\"email\"\n  :as=\"ErrorMessage\"\n\u002F> This is useful when your application has a shared component for validation messages.",{"id":346,"title":234,"titles":347,"content":348,"level":163},"\u002Fcomponents\u002Fnot-message#form",[48,197],"By default, NotMessage uses the form instance provided by a surrounding NotForm. You can explicitly provide a form instance: \u003CNotMessage\n  :form=\"form\"\n  path=\"email\"\n\u002F> An explicit form takes priority over the form provided by a NotForm ancestor. It is required when using NotMessage outside of a NotForm.",{"id":350,"title":249,"titles":351,"content":352,"level":95},"\u002Fcomponents\u002Fnot-message#slot-props",[48],"The default slot receives the current error message: PropTypeDescriptionmessagestring | undefinedThe first active validation error message for the specified field. Because message is optional, it may be undefined when there is no active error. \u003CNotMessage\n  v-slot=\"{ message }\"\n  path=\"email\"\n>\n  \u003Cspan>{{ message }}\u003C\u002Fspan>\n\u003C\u002FNotMessage> Normally, you do not need to check for message yourself because \u003CNotMessage> renders nothing when there is no error.",{"id":354,"title":207,"titles":355,"content":356,"level":95},"\u002Fcomponents\u002Fnot-message#basic-usage",[48],"The most common usage is alongside a NotField: \u003CNotField v-slot=\"{ events, path }\" path=\"email\">\n  \u003Clabel :for=\"path\">Email\u003C\u002Flabel>\n\n  \u003Cinput\n    :id=\"path\"\n    v-model=\"form.values.email\"\n    v-bind=\"events\"\n    type=\"email\"\n  \u002F>\n\n  \u003CNotMessage :path=\"path\" \u002F>\n\u003C\u002FNotField> When validation fails, NotMessage displays the first validation error associated with email. When there are no active errors, it renders nothing.",{"id":358,"title":359,"titles":360,"content":361,"level":95},"\u002Fcomponents\u002Fnot-message#custom-error-display","Custom Error Display",[48],"Use the default slot when you need control over the message markup: \u003CNotField v-slot=\"{ events, path }\" path=\"email\">\n  \u003Cinput\n    :id=\"path\"\n    v-model=\"form.values.email\"\n    v-bind=\"events\"\n    type=\"email\"\n  \u002F>\n\n  \u003CNotMessage\n    v-slot=\"{ message }\"\n    :path=\"path\"\n  >\n    \u003Cspan class=\"error-text\">\n      {{ message }}\n    \u003C\u002Fspan>\n  \u003C\u002FNotMessage>\n\u003C\u002FNotField> This lets you add your own classes, icons, wrappers, or other presentation. For example: \u003CNotMessage\n  v-slot=\"{ message }\"\n  path=\"email\"\n  as=\"p\"\n>\n  \u003Cspan class=\"flex items-center gap-2\">\n    \u003CIcon name=\"tabler:alert-circle\" \u002F>\n    {{ message }}\n  \u003C\u002Fspan>\n\u003C\u002FNotMessage>",{"id":363,"title":364,"titles":365,"content":366,"level":95},"\u002Fcomponents\u002Fnot-message#rendering-as-another-element","Rendering as Another Element",[48],"Use the as prop when you only need to change the underlying element without replacing the slot content: \u003CNotMessage\n  path=\"email\"\n  as=\"p\"\n\u002F> This renders the validation message as a paragraph instead of the default \u003Cspan>.",{"id":368,"title":311,"titles":369,"content":370,"level":95},"\u002Fcomponents\u002Fnot-message#nested-fields",[48],"NotMessage accepts nested field paths using dot notation: \u003CNotField v-slot=\"{ events, path }\" path=\"user.email\">\n  \u003Cinput\n    :id=\"path\"\n    v-model=\"form.values.user.email\"\n    v-bind=\"events\"\n    type=\"email\"\n  \u002F>\n\n  \u003CNotMessage :path=\"path\" \u002F>\n\u003C\u002FNotField> The message is resolved for the exact field path provided.",{"id":372,"title":373,"titles":374,"content":375,"level":95},"\u002Fcomponents\u002Fnot-message#standalone-usage","Standalone Usage",[48],"NotMessage can also be used outside a NotField. When there is no surrounding NotForm, provide the form instance explicitly: \u003CNotMessage\n  :form=\"form\"\n  path=\"email\"\n\u002F> This makes NotMessage useful when the field input and error message are rendered in different parts of the component tree.",{"id":377,"title":378,"titles":379,"content":380,"level":95},"\u002Fcomponents\u002Fnot-message#displaying-multiple-errors","Displaying Multiple Errors",[48],"\u003CNotMessage> intentionally displays only the first active validation error. If you need to display every validation issue for a field, use the field's errors slot prop instead: \u003CNotField\n  v-slot=\"{ events, path, errors }\"\n  path=\"email\"\n>\n  \u003Cinput\n    :id=\"path\"\n    v-model=\"form.values.email\"\n    v-bind=\"events\"\n    type=\"email\"\n  \u002F>\n\n  \u003Cdiv v-if=\"errors.length\">\n    \u003Cp\n      v-for=\"(error, index) in errors\"\n      :key=\"index\"\n    >\n      {{ error.message }}\n    \u003C\u002Fp>\n  \u003C\u002Fdiv>\n\u003C\u002FNotField> This gives you access to the complete StandardSchemaV1.Issue[] returned by validation rather than only the first message.",{"id":382,"title":383,"titles":384,"content":385,"level":95},"\u002Fcomponents\u002Fnot-message#conditional-rendering","Conditional Rendering",[48],"You generally do not need to conditionally render \u003CNotMessage> yourself. It automatically renders nothing when there is no active validation error: \u003CNotField v-slot=\"{ events, path }\" path=\"email\">\n  \u003Cinput\n    :id=\"path\"\n    v-model=\"form.values.email\"\n    v-bind=\"events\"\n    type=\"email\"\n  \u002F>\n\n  \u003CNotMessage :path=\"path\" \u002F>\n\u003C\u002FNotField> This makes it safe to place the component directly below an input without additional error checks.",{"id":387,"title":388,"titles":389,"content":390,"level":95},"\u002Fcomponents\u002Fnot-message#custom-component","Custom Component",[48],"The as prop also accepts a Vue component, making it possible to integrate your own error-message component: \u003CNotMessage\n  :as=\"FormError\"\n  path=\"email\"\n\u002F> The component receives the rendered message through the normal Vue component rendering mechanism. html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}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 .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}",{"id":53,"title":52,"titles":392,"content":393,"level":89},[],"Renderless component for managing dynamic array fields with typed items, stable keys, validation state, and array operations. \u003CNotArrayField> is a renderless component for working with array fields in a form. It provides the current array items, stable keys and field paths for rendering nested fields, validation state, and methods for adding, removing, updating, inserting, swapping, and moving items.",{"id":395,"title":197,"titles":396,"content":397,"level":95},"\u002Fcomponents\u002Fnot-array-field#props",[52],"PropTypeRequiredDescriptionpathstringYesDot-separated path to the array field within the form values.itemSchemaStandardSchemaV1NoSchema for a single array item, used for type inference.formNotFormInstance\u003Cany>NoExplicit form instance override. Takes priority over a NotForm ancestor.validateOnPartial\u003CRecord\u003C'onChange' | 'onMount', boolean>>NoOverrides the form-wide validation triggers for the array field.",{"id":399,"title":229,"titles":400,"content":401,"level":163},"\u002Fcomponents\u002Fnot-array-field#path",[52,197],"path identifies the array field managed by NotArrayField. \u003CNotArrayField path=\"todos\">\n  ...\n\u003C\u002FNotArrayField> Nested array paths are also supported: \u003CNotArrayField path=\"user.todos\">\n  ...\n\u003C\u002FNotArrayField> The same path is exposed through the default slot.",{"id":403,"title":404,"titles":405,"content":406,"level":163},"\u002Fcomponents\u002Fnot-array-field#itemschema","itemSchema",[52,197],"itemSchema describes the schema for a single array item. It is used for type inference so that array mutation methods such as append, prepend, insert, and update receive the correct item type. \u003Cscript setup lang=\"ts\">\nimport { z } from 'zod'\n\nconst itemSchema = z.object({\n  done: z.boolean(),\n  title: z.string(),\n})\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003CNotArrayField\n    v-slot=\"{ append }\"\n    path=\"todos\"\n    :item-schema=\"itemSchema\"\n  >\n    \u003Cbutton\n      type=\"button\"\n      @click=\"append({ title: '', done: false })\"\n    >\n      Add Todo\n    \u003C\u002Fbutton>\n  \u003C\u002FNotArrayField>\n\u003C\u002Ftemplate>",{"id":408,"title":234,"titles":409,"content":410,"level":163},"\u002Fcomponents\u002Fnot-array-field#form",[52,197],"By default, NotArrayField uses the form instance provided by a surrounding NotForm. You can explicitly provide a form instance: \u003CNotArrayField\n  :form=\"form\"\n  path=\"todos\"\n>\n  ...\n\u003C\u002FNotArrayField> An explicit form takes priority over the instance provided by a NotForm ancestor. It is required when using NotArrayField outside of a NotForm.",{"id":412,"title":239,"titles":413,"content":414,"level":163},"\u002Fcomponents\u002Fnot-array-field#validateon",[52,197],"validateOn overrides validation behavior for the array field. The array field supports overrides for onChange and onMount: \u003CNotArrayField\n  path=\"todos\"\n  :validate-on=\"{ onChange: true }\"\n\u002F> Only the specified triggers are overridden. Other form-wide validation settings remain unchanged.",{"id":416,"title":249,"titles":417,"content":418,"level":95},"\u002Fcomponents\u002Fnot-array-field#slot-props",[52],"The default slot receives the full array state and all available array operations. PropTypeDescriptionpathstringThe dot-separated path of the array field.itemsNotArrayFieldItem[]Array items with stable keys, current indexes, and field paths.errorsStandardSchemaV1.Issue[]Validation issues for the array field from the last validation run.isValidbooleanWhether the array field currently has no validation errors.isTouchedbooleanWhether any item in the array has been touched.isDirtybooleanWhether any item in the array differs from its initial value.isValidatingbooleanWhether validation is currently running for the array field.validate() => ReturnType\u003CNotFormInstance\u003CTSchema>['validateField']>Manually triggers validation for the array field.append(value: TItem) => voidAdds an item to the end of the array.prepend(value: TItem) => voidAdds an item to the beginning of the array.insert(index: number, value: TItem) => voidInserts an item at a specific index.remove(index: number) => voidRemoves an item at a specific index.update(index: number, value: TItem) => voidReplaces the value of an item at a specific index.swap(indexA: number, indexB: number) => voidSwaps two items.move(from: number, to: number) => voidMoves an item from one index to another.",{"id":420,"title":421,"titles":422,"content":423,"level":95},"\u002Fcomponents\u002Fnot-array-field#array-items","Array Items",[52],"The items slot prop contains metadata for every item in the array. Each item has: PropertyTypeDescriptionkeystringStable key for Vue rendering.indexnumberCurrent index of the item.pathstringFull field path to the item. For an array at todos, items can have paths such as: todos[0]\ntodos[1]\ntodos[2] The key remains stable when items are reordered, while index and path change with the item's current position.",{"id":425,"title":128,"titles":426,"content":157,"level":95},"\u002Fcomponents\u002Fnot-array-field#demo",[52],{"id":428,"title":429,"titles":430,"content":157,"level":95},"\u002Fcomponents\u002Fnot-array-field#array-operations","Array Operations",[52],{"id":432,"title":433,"titles":434,"content":435,"level":163},"\u002Fcomponents\u002Fnot-array-field#append","Append",[52,429],"Add an item to the end of the array: \u003CNotArrayField v-slot=\"{ append }\" path=\"items\">\n  \u003Cbutton\n    type=\"button\"\n    @click=\"append({ name: 'New Item' })\"\n  >\n    Add Item\n  \u003C\u002Fbutton>\n\u003C\u002FNotArrayField>",{"id":437,"title":438,"titles":439,"content":440,"level":163},"\u002Fcomponents\u002Fnot-array-field#prepend","Prepend",[52,429],"Add an item to the beginning of the array: \u003CNotArrayField v-slot=\"{ prepend }\" path=\"items\">\n  \u003Cbutton\n    type=\"button\"\n    @click=\"prepend({ name: 'First Item' })\"\n  >\n    Add to Start\n  \u003C\u002Fbutton>\n\u003C\u002FNotArrayField>",{"id":442,"title":443,"titles":444,"content":445,"level":163},"\u002Fcomponents\u002Fnot-array-field#insert","Insert",[52,429],"Insert an item at a specific index: \u003CNotArrayField v-slot=\"{ insert }\" path=\"items\">\n  \u003Cbutton\n    type=\"button\"\n    @click=\"insert(2, { name: 'Inserted Item' })\"\n  >\n    Insert at Index 2\n  \u003C\u002Fbutton>\n\u003C\u002FNotArrayField>",{"id":447,"title":448,"titles":449,"content":450,"level":163},"\u002Fcomponents\u002Fnot-array-field#remove","Remove",[52,429],"Remove an item at a specific index: \u003CNotArrayField v-slot=\"{ remove }\" path=\"items\">\n  \u003Cbutton\n    type=\"button\"\n    @click=\"remove(1)\"\n  >\n    Remove Item\n  \u003C\u002Fbutton>\n\u003C\u002FNotArrayField> When rendering the array, use the stable key and current index from items: \u003CNotArrayField\n  v-slot=\"{ items, remove }\"\n  path=\"items\"\n>\n  \u003Cdiv\n    v-for=\"item in items\"\n    :key=\"item.key\"\n  >\n    \u003Cspan>\n      {{ form.values.items[item.index].name }}\n    \u003C\u002Fspan>\n\n    \u003Cbutton\n      type=\"button\"\n      @click=\"remove(item.index)\"\n    >\n      Remove\n    \u003C\u002Fbutton>\n  \u003C\u002Fdiv>\n\u003C\u002FNotArrayField>",{"id":452,"title":453,"titles":454,"content":455,"level":163},"\u002Fcomponents\u002Fnot-array-field#update","Update",[52,429],"Replace an item at a specific index: \u003CNotArrayField v-slot=\"{ update }\" path=\"items\">\n  \u003Cbutton\n    type=\"button\"\n    @click=\"update(0, { name: 'Updated Item' })\"\n  >\n    Update First Item\n  \u003C\u002Fbutton>\n\u003C\u002FNotArrayField> update replaces the value at the specified index without changing the length of the array.",{"id":457,"title":458,"titles":459,"content":460,"level":163},"\u002Fcomponents\u002Fnot-array-field#swap","Swap",[52,429],"Swap two items: \u003CNotArrayField v-slot=\"{ swap }\" path=\"items\">\n  \u003Cbutton\n    type=\"button\"\n    @click=\"swap(0, 1)\"\n  >\n    Swap First Two\n  \u003C\u002Fbutton>\n\u003C\u002FNotArrayField>",{"id":462,"title":463,"titles":464,"content":465,"level":163},"\u002Fcomponents\u002Fnot-array-field#move","Move",[52,429],"Move an item from one index to another: \u003CNotArrayField v-slot=\"{ move }\" path=\"items\">\n  \u003Cbutton\n    type=\"button\"\n    @click=\"move(0, 5)\"\n  >\n    Move First to Last\n  \u003C\u002Fbutton>\n\u003C\u002FNotArrayField>",{"id":467,"title":468,"titles":469,"content":470,"level":95},"\u002Fcomponents\u002Fnot-array-field#stable-keys","Stable Keys",[52],"NotArrayField provides a stable key for each item. Use it as the Vue v-for key: \u003CNotArrayField\n  v-slot=\"{ items }\"\n  path=\"items\"\n>\n  \u003Cdiv\n    v-for=\"item in items\"\n    :key=\"item.key\"\n  >\n    ...\n  \u003C\u002Fdiv>\n\u003C\u002FNotArrayField> Do not use the array index as the Vue key for managed array items: \u003C!-- Avoid -->\n\u003Cdiv\n  v-for=\"(item, index) in form.values.items\"\n  :key=\"index\"\n>\n  ...\n\u003C\u002Fdiv> The provided key remains stable when items are reordered, allowing Vue to correctly track each item.",{"id":472,"title":473,"titles":474,"content":475,"level":95},"\u002Fcomponents\u002Fnot-array-field#using-item-paths","Using Item Paths",[52],"Each item exposes a path that can be passed to nested fields. For an item in todos: todos[0] A nested field can extend that path: todos[0].title Example: \u003CNotArrayField\n  path=\"todos\"\n  v-slot=\"{ items }\"\n>\n  \u003Cdiv\n    v-for=\"item in items\"\n    :key=\"item.key\"\n  >\n    \u003CNotField\n      v-slot=\"{ events }\"\n      :path=\"`${item.path}.title`\"\n    >\n      \u003Cinput\n        v-model=\"form.values.todos[item.index].title\"\n        v-bind=\"events\"\n      \u002F>\n\n      \u003CNotMessage :path=\"`${item.path}.title`\" \u002F>\n    \u003C\u002FNotField>\n  \u003C\u002Fdiv>\n\u003C\u002FNotArrayField> This keeps field paths tied to the current position of each item.",{"id":477,"title":478,"titles":479,"content":480,"level":95},"\u002Fcomponents\u002Fnot-array-field#array-validation","Array Validation",[52],"NotArrayField exposes validation state for the array through the slot. \u003CNotArrayField\n  path=\"todos\"\n  v-slot=\"{\n    errors,\n    isValid,\n    isTouched,\n    isDirty,\n    isValidating,\n  }\"\n>\n  \u003Cp v-if=\"isValid\">\n    Array is valid.\n  \u003C\u002Fp>\n\n  \u003Cp v-if=\"isTouched\">\n    Array has been touched.\n  \u003C\u002Fp>\n\n  \u003Cp v-if=\"isDirty\">\n    Array has been modified.\n  \u003C\u002Fp>\n\n  \u003Cp v-if=\"isValidating\">\n    Validating...\n  \u003C\u002Fp>\n\n  \u003Cul v-if=\"errors.length\">\n    \u003Cli\n      v-for=\"(error, index) in errors\"\n      :key=\"index\"\n    >\n      {{ error.message }}\n    \u003C\u002Fli>\n  \u003C\u002Ful>\n\u003C\u002FNotArrayField> The errors slot prop contains all validation issues reported for the array field during the last validation run.",{"id":482,"title":273,"titles":483,"content":484,"level":163},"\u002Fcomponents\u002Fnot-array-field#istouched",[52,478],"isTouched indicates whether any item in the array has been touched.",{"id":486,"title":278,"titles":487,"content":488,"level":163},"\u002Fcomponents\u002Fnot-array-field#isdirty",[52,478],"isDirty indicates whether any item in the array differs from its initial value.",{"id":490,"title":283,"titles":491,"content":492,"level":163},"\u002Fcomponents\u002Fnot-array-field#isvalidating",[52,478],"isValidating indicates that validation is currently running for the array field.",{"id":494,"title":268,"titles":495,"content":496,"level":163},"\u002Fcomponents\u002Fnot-array-field#isvalid",[52,478],"isValid indicates whether the array currently has no validation errors.",{"id":498,"title":499,"titles":500,"content":501,"level":95},"\u002Fcomponents\u002Fnot-array-field#manual-validation","Manual Validation",[52],"Use validate to manually trigger validation for the array: \u003CNotArrayField\n  path=\"todos\"\n  v-slot=\"{ validate }\"\n>\n  \u003Cbutton\n    type=\"button\"\n    @click=\"validate\"\n  >\n    Validate Todos\n  \u003C\u002Fbutton>\n\u003C\u002FNotArrayField> This is useful when array changes are performed programmatically and validation needs to be triggered explicitly.",{"id":503,"title":504,"titles":505,"content":506,"level":95},"\u002Fcomponents\u002Fnot-array-field#nested-arrays","Nested Arrays",[52],"NotArrayField can be nested to manage arrays inside array items. For example: const numberArraySchema = z.array(z.number())\nconst schema = z.object({\n  matrix: z.array(numberArraySchema),\n}) The outer array can provide the path for each row: \u003CNotArrayField\n  path=\"matrix\"\n  v-slot=\"{ items: rows }\"\n>\n  \u003Cdiv\n    v-for=\"row in rows\"\n    :key=\"row.key\"\n  >\n    \u003CNotArrayField\n      :path=\"row.path\"\n      v-slot=\"{ items: cells }\"\n    >\n      \u003Cdiv\n        v-for=\"cell in cells\"\n        :key=\"cell.key\"\n      >\n        \u003CNotField\n          v-slot=\"{ events }\"\n          :path=\"cell.path\"\n        >\n          \u003Cinput\n            v-model=\"form.values.matrix[row.index][cell.index]\"\n            v-bind=\"events\"\n            type=\"number\"\n          \u002F>\n        \u003C\u002FNotField>\n      \u003C\u002Fdiv>\n    \u003C\u002FNotArrayField>\n  \u003C\u002Fdiv>\n\u003C\u002FNotArrayField> Each nested NotArrayField receives its parent's item path, allowing the same API to be composed for deeper array structures. html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}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 .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sfNiH, html code.shiki .sfNiH{--shiki-light:#FF5370;--shiki-default:#FF9CAC;--shiki-dark:#FF9CAC}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}",{"id":62,"title":61,"titles":508,"content":509,"level":89},[],"Create a type-safe form instance with schema validation, reactive state, field tracking, and submission handling. useNotForm is the core composable for creating and managing a NotForm instance. It connects a Standard Schema-compatible validator to a deeply reactive form state and provides everything needed to manage values, validation, field interaction, errors, submission, and reset behavior. The returned form instance can be used directly or provided to \u003CNotForm> for use by descendant field components.",{"id":511,"title":512,"titles":513,"content":514,"level":95},"\u002Fcomposables\u002Fuse-not-form#signature","Signature",[61],"function useNotForm\u003CTSchema extends ObjectSchema>(\n  config: UseNotFormConfig\u003CTSchema>,\n): NotFormInstance\u003CTSchema> The generic type is inferred from the supplied schema. The schema drives the types of: form.valuesform.setValue()field pathsvalidation resultsonSubmit()form.validateField()form.reset()",{"id":516,"title":517,"titles":518,"content":519,"level":95},"\u002Fcomposables\u002Fuse-not-form#configuration","Configuration",[61],"useNotForm accepts a UseNotFormConfig object.",{"id":521,"title":522,"titles":523,"content":524,"level":163},"\u002Fcomposables\u002Fuse-not-form#schema","schema",[61,517],"schema: MaybeRefOrGetter\u003CTSchema> The validation schema used to parse and validate form data. The schema can be provided directly or through a Vue ref or getter. import { z } from 'zod'\n\nconst schema = z.object({\n  email: z.email(),\n  password: z.string().min(8),\n})\n\nconst form = useNotForm({\n  schema,\n\n  onSubmit(values) {\n    console.log(values)\n  },\n}) The schema must be a Standard Schema-compatible object whose input is an object. The schema also determines the output passed to onSubmit. For example, a schema can transform its input: const schema = z.object({\n  age: z.coerce.number(),\n})\n\nconst form = useNotForm({\n  schema,\n\n  onSubmit(values) {\n    \u002F\u002F `values.age` is the schema's output type\n    console.log(values.age)\n  },\n})",{"id":526,"title":527,"titles":528,"content":529,"level":163},"\u002Fcomposables\u002Fuse-not-form#initialvalues","initialValues",[61,517],"initialValues?: DeepPartial\u003CStandardSchemaV1.InferInput\u003CTSchema>> The initial values for the form. The supplied values become the form's initial baseline and are used for: populating form.valuesdirty-state comparisonsform.reset() Because the type is deeply partial, nested values do not necessarily need to be supplied in full. const form = useNotForm({\n  schema,\n\n  initialValues: {\n    email: 'user@example.com',\n    profile: {\n      name: 'Jane',\n    },\n  },\n\n  onSubmit(values) {\n    console.log(values)\n  },\n}) When initialValues is omitted, the form starts from an empty object. The stored baseline is exposed through form.initialValues.",{"id":531,"title":532,"titles":533,"content":534,"level":163},"\u002Fcomposables\u002Fuse-not-form#initialerrors","initialErrors",[61,517],"initialErrors?: StandardSchemaV1.Issue[] Initial validation issues for the form. This is useful when a form needs to start with errors returned from another source, such as previously persisted validation state. const form = useNotForm({\n  schema,\n\n  initialErrors: [\n    {\n      message: 'This email is already registered.',\n      path: ['email'],\n    },\n  ],\n\n  onSubmit(values) {\n    console.log(values)\n  },\n}) The errors become the form's initial error baseline and are exposed through form.initialErrors.",{"id":536,"title":239,"titles":537,"content":538,"level":163},"\u002Fcomposables\u002Fuse-not-form#validateon",[61,517],"validateOn?: Partial\u003CRecord\u003CValidationTrigger, boolean>> Controls which interaction events trigger validation. Available triggers are: type ValidationTrigger\n  = | 'onBlur'\n    | 'onChange'\n    | 'onFocus'\n    | 'onInput'\n    | 'onMount' The default configuration is: {\n  onBlur: true,\n  onChange: true,\n  onFocus: false,\n  onInput: true,\n  onMount: false,\n} Only the values you provide are overridden. For example: const form = useNotForm({\n  schema,\n\n  validateOn: {\n    onBlur: true,\n    onInput: false,\n  },\n\n  onSubmit(values) {\n    console.log(values)\n  },\n}) The resolved configuration is available through form.validateOn. Individual field components can override supported triggers on a per-field basis.",{"id":540,"title":541,"titles":542,"content":543,"level":163},"\u002Fcomposables\u002Fuse-not-form#validationmode","validationMode",[61,517],"validationMode?: 'eager' | 'lazy' Controls how validation is applied after field interaction. The default is: validationMode: 'eager'",{"id":545,"title":546,"titles":547,"content":548,"level":549},"\u002Fcomposables\u002Fuse-not-form#eager","eager",[61,517,541],"After a field has an error, subsequent changes can continue to validate it immediately.",4,{"id":551,"title":552,"titles":553,"content":554,"level":549},"\u002Fcomposables\u002Fuse-not-form#lazy","lazy",[61,517,541],"Validation is deferred until blur or submission. const form = useNotForm({\n  schema,\n\n  validationMode: 'lazy',\n\n  onSubmit(values) {\n    console.log(values)\n  },\n}) The resolved mode is exposed through form.validationMode.",{"id":556,"title":557,"titles":558,"content":559,"level":163},"\u002Fcomposables\u002Fuse-not-form#onsubmit","onSubmit",[61,517],"onSubmit?: (\n  values: StandardSchemaV1.InferOutput\u003CTSchema>\n) => Promise\u003Cvoid> | void Called after the complete form has been validated successfully. The callback receives the schema's output type, not necessarily its raw input type. const form = useNotForm({\n  schema,\n\n  async onSubmit(values) {\n    await saveUser(values)\n  },\n}) onSubmit is optional. A form can still be created and validated without providing a submit callback.",{"id":561,"title":562,"titles":563,"content":564,"level":95},"\u002Fcomposables\u002Fuse-not-form#returned-form-instance","Returned Form Instance",[61],"useNotForm returns a NotFormInstance. const form = useNotForm({\n  onSubmit,\n  schema,\n}) The instance contains the form's baseline state, reactive values, validation configuration, field tracking, errors, validation methods, submission state, and reset API.",{"id":566,"title":567,"titles":568,"content":157,"level":95},"\u002Fcomposables\u002Fuse-not-form#baseline-state","Baseline State",[61],{"id":570,"title":527,"titles":571,"content":572,"level":163},"\u002Fcomposables\u002Fuse-not-form#initialvalues-1",[61,567],"readonly initialValues: DeepPartial\u003CStandardSchemaV1.InferInput\u003CTSchema>> The values currently used as the form's baseline. These are the values used when determining whether fields are dirty. form.initialValues Calling reset() without arguments restores these values. When new values are provided to reset(), they replace this baseline.",{"id":574,"title":532,"titles":575,"content":576,"level":163},"\u002Fcomposables\u002Fuse-not-form#initialerrors-1",[61,567],"readonly initialErrors: StandardSchemaV1.Issue[] The errors currently used as the form's error baseline. form.initialErrors Calling reset() restores these errors. Providing new errors to reset() replaces this baseline.",{"id":578,"title":579,"titles":580,"content":157,"level":95},"\u002Fcomposables\u002Fuse-not-form#validation-configuration","Validation Configuration",[61],{"id":582,"title":239,"titles":583,"content":584,"level":163},"\u002Fcomposables\u002Fuse-not-form#validateon-1",[61,579],"readonly validateOn: {\n  onBlur: boolean\n  onChange: boolean\n  onFocus: boolean\n  onInput: boolean\n  onMount: boolean\n} The resolved validation triggers for the form. Unlike the optional validateOn passed to useNotForm, this property always contains all trigger keys. console.log(form.validateOn.onBlur)\nconsole.log(form.validateOn.onInput)",{"id":586,"title":541,"titles":587,"content":588,"level":163},"\u002Fcomposables\u002Fuse-not-form#validationmode-1",[61,579],"readonly validationMode: 'eager' | 'lazy' The resolved validation mode for the form: console.log(form.validationMode)",{"id":590,"title":591,"titles":592,"content":157,"level":95},"\u002Fcomposables\u002Fuse-not-form#values","Values",[61],{"id":594,"title":595,"titles":596,"content":597,"level":163},"\u002Fcomposables\u002Fuse-not-form#values-1","values",[61,591],"values: StandardSchemaV1.InferInput\u003CTSchema> values is the deeply reactive object containing the current form values. It can be accessed directly: console.log(form.values.email) Because it is reactive, it can also be used directly with v-model: \u003Cinput v-model=\"form.values.email\" \u002F> Nested values work the same way: \u003Cinput v-model=\"form.values.address.city\" \u002F>",{"id":599,"title":600,"titles":601,"content":602,"level":163},"\u002Fcomposables\u002Fuse-not-form#setvaluepath-value","setValue(path, value)",[61,591],"setValue(\n  path: Paths\u003CStandardSchemaV1.InferInput\u003CTSchema>>,\n  value: Get\u003CStandardSchemaV1.InferInput\u003CTSchema>, path>,\n): void Sets a value using a dot-separated field path. This is useful for custom inputs or deeply nested values where v-model is not appropriate. form.setValue('email', 'user@example.com')\n\nform.setValue('address.city', 'Lagos') The field path and value are typed from the schema. Calling setValue() also updates dirty tracking by comparing the new value with the current initialValues. If the value matches its initial value again, that field is removed from dirtyFields. setValue() does not itself trigger validation. Validation is driven by the configured field interaction handlers.",{"id":604,"title":605,"titles":606,"content":157,"level":95},"\u002Fcomposables\u002Fuse-not-form#touched-state","Touched State",[61],{"id":608,"title":609,"titles":610,"content":611,"level":163},"\u002Fcomposables\u002Fuse-not-form#touchedfields","touchedFields",[61,605],"touchedFields: Set\u003CPaths\u003CStandardSchemaV1.InferInput\u003CTSchema>>> The set of field paths that have been marked as touched. console.log(form.touchedFields) A field is normally marked as touched by its NotField blur handler. During submission, all existing field paths are marked as touched so validation feedback can surface across the form.",{"id":613,"title":273,"titles":614,"content":615,"level":163},"\u002Fcomposables\u002Fuse-not-form#istouched",[61,605],"isTouched: ComputedRef\u003Cboolean> Indicates whether any field in the form has been touched. \u003Cp v-if=\"form.isTouched\">\n  The form has been touched.\n\u003C\u002Fp> In JavaScript or TypeScript, use .value: if (form.isTouched.value) {\n  console.log('Form has been touched')\n}",{"id":617,"title":618,"titles":619,"content":620,"level":163},"\u002Fcomposables\u002Fuse-not-form#touchfieldpath","touchField(path)",[61,605],"touchField(\n  path: Paths\u003CStandardSchemaV1.InferInput\u003CTSchema>>,\n): void Marks a specific field as touched. form.touchField('email') This is normally handled automatically by field components but is useful for custom form controls.",{"id":622,"title":623,"titles":624,"content":157,"level":95},"\u002Fcomposables\u002Fuse-not-form#dirty-state","Dirty State",[61],{"id":626,"title":627,"titles":628,"content":629,"level":163},"\u002Fcomposables\u002Fuse-not-form#dirtyfields","dirtyFields",[61,623],"dirtyFields: Set\u003CPaths\u003CStandardSchemaV1.InferInput\u003CTSchema>>> The set of field paths whose values currently differ from initialValues. console.log(form.dirtyFields)",{"id":631,"title":278,"titles":632,"content":633,"level":163},"\u002Fcomposables\u002Fuse-not-form#isdirty",[61,623],"isDirty: ComputedRef\u003Cboolean> Indicates whether any field is dirty. \u003Cp v-if=\"form.isDirty\">\n  You have unsaved changes.\n\u003C\u002Fp> In JavaScript: if (form.isDirty.value) {\n  console.log('Form has unsaved changes')\n}",{"id":635,"title":636,"titles":637,"content":638,"level":163},"\u002Fcomposables\u002Fuse-not-form#dirtyfieldpath","dirtyField(path)",[61,623],"dirtyField(\n  path: Paths\u003CStandardSchemaV1.InferInput\u003CTSchema>>,\n): void Manually marks a field as dirty. form.dirtyField('email') Normal field interactions update dirty tracking automatically.",{"id":640,"title":641,"titles":642,"content":157,"level":95},"\u002Fcomposables\u002Fuse-not-form#errors","Errors",[61],{"id":644,"title":263,"titles":645,"content":646,"level":163},"\u002Fcomposables\u002Fuse-not-form#errors-1",[61,641],"errors: StandardSchemaV1.Issue[] The raw validation issues produced by the most recent validation run. console.log(form.errors) Each issue contains the path and message supplied by the validation schema. for (const error of form.errors) {\n  console.log(error.path)\n  console.log(error.message)\n}",{"id":648,"title":649,"titles":650,"content":651,"level":163},"\u002Fcomposables\u002Fuse-not-form#errorsmap","errorsMap",[61,641],"errorsMap: ComputedRef\u003C\n  Partial\u003CRecord\u003CPaths\u003CStandardSchemaV1.InferInput\u003CTSchema>>, string>>\n> A convenient flat map of field paths to their first active error message. form.errorsMap.email\nform.errorsMap['address.city'] For example: \u003Cp v-if=\"form.errorsMap.email\">\n  {{ form.errorsMap.email }}\n\u003C\u002Fp> errorsMap is useful when you only need the first message for a field. Use errors or getFieldErrors() when you need the complete validation issues.",{"id":653,"title":654,"titles":655,"content":656,"level":163},"\u002Fcomposables\u002Fuse-not-form#seterrorerror","setError(error)",[61,641],"setError(error: StandardSchemaV1.Issue): void Adds or replaces the error for a specific path. If an issue already exists for the same normalized path, it is replaced. form.setError({\n  message: 'This email is already registered.',\n  path: ['email'],\n}) This is useful for server-side validation errors.",{"id":658,"title":659,"titles":660,"content":661,"level":163},"\u002Fcomposables\u002Fuse-not-form#seterrorserrors","setErrors(errors)",[61,641],"setErrors(errors: StandardSchemaV1.Issue[]): void Replaces all active errors. form.setErrors([\n  {\n    message: 'Email is already registered.',\n    path: ['email'],\n  },\n  {\n    message: 'Username is already taken.',\n    path: ['username'],\n  },\n])",{"id":663,"title":664,"titles":665,"content":666,"level":163},"\u002Fcomposables\u002Fuse-not-form#clearerrors","clearErrors()",[61,641],"clearErrors(): void Removes every active validation error. form.clearErrors()",{"id":668,"title":669,"titles":670,"content":671,"level":163},"\u002Fcomposables\u002Fuse-not-form#getfielderrorspath","getFieldErrors(path)",[61,641],"getFieldErrors(\n  path: Paths\u003CStandardSchemaV1.InferInput\u003CTSchema>>,\n): StandardSchemaV1.Issue[] Returns all active validation issues associated with a particular field path. const errors = form.getFieldErrors('email') Unlike errorsMap, this does not discard additional issues for the same field. for (const error of form.getFieldErrors('email')) {\n  console.log(error.message)\n}",{"id":673,"title":674,"titles":675,"content":157,"level":95},"\u002Fcomposables\u002Fuse-not-form#validation","Validation",[61],{"id":677,"title":283,"titles":678,"content":679,"level":163},"\u002Fcomposables\u002Fuse-not-form#isvalidating",[61,674],"isValidating: Ref\u003Cboolean> Indicates whether one or more validation operations are currently running. \u003Cp v-if=\"form.isValidating\">\n  Validating...\n\u003C\u002Fp> The state remains active while concurrent validation operations are still pending.",{"id":681,"title":682,"titles":683,"content":684,"level":163},"\u002Fcomposables\u002Fuse-not-form#validate","validate()",[61,674],"validate(): Promise\u003C\n  StandardSchemaV1.Result\u003C\n    StandardSchemaV1.InferOutput\u003CTSchema>\n  >\n> Validates the entire form against the current schema. const result = await form.validate() When validation succeeds: const result = await form.validate()\n\nif ('value' in result) {\n  console.log(result.value)\n} When validation fails, the returned result contains issues and those issues replace the form's current errors. A successful validation clears the current errors.",{"id":686,"title":687,"titles":688,"content":689,"level":163},"\u002Fcomposables\u002Fuse-not-form#validatefieldpath","validateField(path)",[61,674],"validateField(\n  path: Paths\u003CStandardSchemaV1.InferInput\u003CTSchema>>,\n): Promise\u003CStandardSchemaV1.Result\u003C...>> Validates a single field against the complete schema. const result = await form.validateField('email') validateField() only replaces errors associated with that field. Errors belonging to other fields remain untouched. When the validation result contains issues, only issues matching the requested path are added to the form's error state. For successful validation, the field's current value is returned. This is useful when building custom inputs that need to validate themselves without validating the entire form.",{"id":691,"title":692,"titles":693,"content":157,"level":95},"\u002Fcomposables\u002Fuse-not-form#form-validity","Form Validity",[61],{"id":695,"title":268,"titles":696,"content":697,"level":163},"\u002Fcomposables\u002Fuse-not-form#isvalid",[61,692],"isValid: ComputedRef\u003Cboolean> Indicates whether the form currently has no active validation errors. \u003Cbutton\n  type=\"submit\"\n  :disabled=\"!form.isValid\"\n>\n  Submit\n\u003C\u002Fbutton> In JavaScript: if (form.isValid.value) {\n  console.log('The form is valid')\n} isValid is based on the current errors collection. It does not independently execute validation.",{"id":699,"title":700,"titles":701,"content":157,"level":95},"\u002Fcomposables\u002Fuse-not-form#submission","Submission",[61],{"id":703,"title":704,"titles":705,"content":706,"level":163},"\u002Fcomposables\u002Fuse-not-form#issubmitting","isSubmitting",[61,700],"isSubmitting: Ref\u003Cboolean> Indicates whether the form's onSubmit handler is currently running. \u003Cbutton\n  type=\"submit\"\n  :disabled=\"form.isSubmitting\"\n>\n  {{ form.isSubmitting ? 'Submitting...' : 'Submit' }}\n\u003C\u002Fbutton>",{"id":708,"title":709,"titles":710,"content":711,"level":163},"\u002Fcomposables\u002Fuse-not-form#submitevent","submit(event)",[61,700],"submit(event: SubmitEvent): Promise\u003Cvoid> Submits the form. The method: Prevents the browser's native form submission.Marks all existing field paths as touched.Marks all existing field paths as dirty.Validates the complete form.Aborts when validation fails.Calls onSubmit with the schema's validated output when validation succeeds. Bind it directly to a native \u003Cform>: \u003Cform @submit=\"form.submit\">\n  ...\n\u003C\u002Fform> Example: \u003Cform @submit=\"form.submit\">\n  \u003Cinput v-model=\"form.values.email\" \u002F>\n\n  \u003Cbutton\n    type=\"submit\"\n    :disabled=\"form.isSubmitting\"\n  >\n    {{ form.isSubmitting ? 'Submitting...' : 'Submit' }}\n  \u003C\u002Fbutton>\n\u003C\u002Fform> When validation fails, onSubmit is not called. When no onSubmit callback was provided, the form still performs validation but has no submission callback to execute.",{"id":713,"title":714,"titles":715,"content":157,"level":95},"\u002Fcomposables\u002Fuse-not-form#reset","Reset",[61],{"id":717,"title":718,"titles":719,"content":720,"level":163},"\u002Fcomposables\u002Fuse-not-form#reset-1","reset()",[61,714],"reset(\n  values?: DeepPartial\u003CStandardSchemaV1.InferInput\u003CTSchema>>,\n  errors?: StandardSchemaV1.Issue[],\n): void Resets the form and clears all touched and dirty tracking. Calling reset() without arguments restores the current initialValues and initialErrors: form.reset()",{"id":722,"title":723,"titles":724,"content":725,"level":163},"\u002Fcomposables\u002Fuse-not-form#reset-with-new-values","Reset With New Values",[61,714],"Pass new values to replace the current baseline: form.reset({\n  email: 'jane@example.com',\n  name: 'Jane',\n}) Those values become the new initialValues. A later call to: form.reset() will restore these values.",{"id":727,"title":728,"titles":729,"content":730,"level":163},"\u002Fcomposables\u002Fuse-not-form#reset-with-new-errors","Reset With New Errors",[61,714],"You can provide both values and errors: form.reset(\n  {\n    email: 'jane@example.com',\n    name: 'Jane',\n  },\n  [\n    {\n      message: 'Email requires verification.',\n      path: ['email'],\n    },\n  ],\n) The supplied errors become the new initialErrors. Calling reset() afterward restores both the new values and those errors.",{"id":732,"title":733,"titles":734,"content":735,"level":163},"\u002Fcomposables\u002Fuse-not-form#reset-only-values","Reset Only Values",[61,714],"Because the two parameters are positional, passing new values while keeping existing baseline errors is possible: form.reset({\n  email: 'new@example.com',\n}) The existing initialErrors remain unchanged.",{"id":737,"title":738,"titles":739,"content":740,"level":163},"\u002Fcomposables\u002Fuse-not-form#reset-only-errors","Reset Only Errors",[61,714],"To replace only the baseline errors while leaving the current baseline values unchanged: form.reset(undefined, [\n  {\n    message: 'Email requires verification.',\n    path: ['email'],\n  },\n]) html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sHdIc, html code.shiki .sHdIc{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#EEFFFF;--shiki-default-font-style:italic;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}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 .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .sfNiH, html code.shiki .sfNiH{--shiki-light:#FF5370;--shiki-default:#FF9CAC;--shiki-dark:#FF9CAC}",{"id":72,"title":71,"titles":742,"content":743,"level":89},[],"Understand validation modes, validation triggers, field-level overrides, and manual validation in NotForm. NotForm separates when validation runs from how validation behaves after a field has been validated. This gives you two controls: validateOn controls which interactions trigger validation.validationMode controls when an errored field is validated again after it changes. This distinction is important because input, blur, and change are not validation modes in the current API. They are validation triggers.",{"id":745,"title":746,"titles":747,"content":748,"level":95},"\u002Fadvanced\u002Fvalidation-modes#the-two-validation-controls","The Two Validation Controls",[71],"A form can be configured with: const form = useNotForm({\n  schema,\n\n  validateOn: {\n    onBlur: true,\n    onChange: true,\n    onInput: true,\n  },\n\n  validationMode: 'eager',\n\n  onSubmit(values) {\n    console.log(values)\n  },\n})",{"id":750,"title":239,"titles":751,"content":752,"level":163},"\u002Fadvanced\u002Fvalidation-modes#validateon",[71,746],"validateOn determines which interactions can start validation. NotForm supports five triggers: TriggerWhen it runsonBlurWhen a field loses focusonChangeWhen a field's value is committedonInputWhen a field's value changes while the user is typingonFocusWhen a field receives focusonMountWhen a field is mounted The default configuration is: {\n  onBlur: true,\n  onChange: true,\n  onFocus: false,\n  onInput: true,\n  onMount: false,\n} These defaults are resolved onto form.validateOn. console.log(form.validateOn.onBlur)\nconsole.log(form.validateOn.onInput)",{"id":754,"title":541,"titles":755,"content":756,"level":163},"\u002Fadvanced\u002Fvalidation-modes#validationmode",[71,746],"validationMode currently has two values: type ValidationMode = 'eager' | 'lazy' The default is: validationMode: 'eager' The mode does not select an event such as blur or input. Instead, it determines how validation behaves around existing errors.",{"id":758,"title":759,"titles":760,"content":761,"level":95},"\u002Fadvanced\u002Fvalidation-modes#eager-mode","Eager Mode",[71],"With eager, a field can continue validating during subsequent changes once it is in an errored state. This is useful when you want the error to disappear as soon as the user fixes the value. const form = useNotForm({\n  schema,\n\n  validationMode: 'eager',\n\n  validateOn: {\n    onBlur: true,\n    onInput: true,\n  },\n\n  onSubmit(values) {\n    console.log(values)\n  },\n}) For example, imagine a required email field: User focuses the field\n        ↓\nUser leaves it empty\n        ↓\nBlur validation\n        ↓\n\"Email is required\"\n        ↓\nUser starts typing\n        ↓\nInput validation continues\n        ↓\nError disappears once the value validates Eager mode is generally the better choice for forms where validation feedback should become progressively more responsive after an error has been shown.",{"id":763,"title":764,"titles":765,"content":766,"level":95},"\u002Fadvanced\u002Fvalidation-modes#lazy-mode","Lazy Mode",[71],"With lazy, validation is deferred until blur or submission. const form = useNotForm({\n  schema,\n\n  validationMode: 'lazy',\n\n  onSubmit(values) {\n    console.log(values)\n  },\n}) This is useful when you want a less intrusive validation experience. A user can type through an invalid intermediate state without constantly re-running validation. For example: User starts typing\n        ↓\nIntermediate value may be invalid\n        ↓\nNo repeated validation while editing\n        ↓\nUser leaves the field\n        ↓\nValidation runs Lazy mode is especially useful for fields where valid input requires several keystrokes before the value becomes meaningful.",{"id":768,"title":128,"titles":769,"content":157,"level":95},"\u002Fadvanced\u002Fvalidation-modes#demo",[71],{"id":771,"title":772,"titles":773,"content":774,"level":95},"\u002Fadvanced\u002Fvalidation-modes#choosing-validation-triggers","Choosing Validation Triggers",[71],"The triggers and mode can be combined.",{"id":776,"title":777,"titles":778,"content":779,"level":163},"\u002Fadvanced\u002Fvalidation-modes#blur-validation","Blur Validation",[71,772],"Blur validation is a good default for most form fields: const form = useNotForm({\n  schema,\n\n  validateOn: {\n    onBlur: true,\n    onChange: false,\n    onInput: false,\n  },\n\n  onSubmit(values) {\n    console.log(values)\n  },\n}) This avoids validating every intermediate value while the user is typing.",{"id":781,"title":782,"titles":783,"content":784,"level":163},"\u002Fadvanced\u002Fvalidation-modes#input-validation","Input Validation",[71,772],"Enable onInput when feedback should happen while the value is being entered: const form = useNotForm({\n  schema,\n\n  validateOn: {\n    onInput: true,\n  },\n\n  onSubmit(values) {\n    console.log(values)\n  },\n}) This is useful for fields such as: password requirementsusernameslive formatting constraintsshort fields where immediate feedback is valuable It can be expensive for asynchronous validation because every input interaction can start a validation run.",{"id":786,"title":787,"titles":788,"content":789,"level":163},"\u002Fadvanced\u002Fvalidation-modes#change-validation","Change Validation",[71,772],"onChange validates when the value is committed. const form = useNotForm({\n  schema,\n\n  validateOn: {\n    onChange: true,\n  },\n\n  onSubmit(values) {\n    console.log(values)\n  },\n}) This can work well with selects, checkboxes, toggles, and other controls where a committed value is more meaningful than every intermediate interaction.",{"id":791,"title":792,"titles":793,"content":794,"level":163},"\u002Fadvanced\u002Fvalidation-modes#focus-validation","Focus Validation",[71,772],"Focus validation is available when a field needs to validate as soon as it receives focus: const form = useNotForm({\n  schema,\n\n  validateOn: {\n    onFocus: true,\n  },\n\n  onSubmit(values) {\n    console.log(values)\n  },\n}) It is disabled by default.",{"id":796,"title":797,"titles":798,"content":799,"level":163},"\u002Fadvanced\u002Fvalidation-modes#mount-validation","Mount Validation",[71,772],"onMount validates when a field is mounted. const form = useNotForm({\n  schema,\n\n  validateOn: {\n    onMount: true,\n  },\n\n  onSubmit(values) {\n    console.log(values)\n  },\n}) This can be useful for forms whose initial state should immediately be evaluated. It is disabled by default.",{"id":801,"title":802,"titles":803,"content":804,"level":95},"\u002Fadvanced\u002Fvalidation-modes#combining-triggers","Combining Triggers",[71],"Triggers are independent. You can enable several at once: const form = useNotForm({\n  schema,\n\n  validateOn: {\n    onBlur: true,\n    onChange: true,\n    onInput: true,\n  },\n\n  onSubmit(values) {\n    console.log(values)\n  },\n}) Or selectively disable one: const form = useNotForm({\n  schema,\n\n  validateOn: {\n    onBlur: true,\n    onChange: true,\n    onInput: false,\n  },\n\n  onSubmit(values) {\n    console.log(values)\n  },\n}) Because validateOn is partial, only the triggers you specify are overridden.",{"id":806,"title":807,"titles":808,"content":809,"level":95},"\u002Fadvanced\u002Fvalidation-modes#per-field-configuration","Per-Field Configuration",[71],"Individual fields can override the form-wide trigger configuration. \u003CNotField\n  path=\"username\"\n  :validate-on=\"{ onInput: true }\"\n  v-slot=\"{ events }\"\n>\n  \u003Cinput\n    v-model=\"form.values.username\"\n    v-bind=\"events\"\n  \u002F>\n\u003C\u002FNotField> This lets the form keep one general strategy while giving specific fields different behavior. For example: Form\n├── name       → blur\n├── email      → blur\n├── username   → input\n└── password   → blur See \u003CNotField> for field-level configuration.",{"id":811,"title":812,"titles":813,"content":814,"level":95},"\u002Fadvanced\u002Fvalidation-modes#validation-on-submission","Validation on Submission",[71],"Submission always performs complete form validation. \u003Cform @submit=\"form.submit\">\n  ...\n\u003C\u002Fform> form.submit(): prevents the browser's native submissionmarks all existing fields as touchedmarks all existing fields as dirtyvalidates the entire formaborts when validation failscalls onSubmit only when validation succeeds This means the validation configuration cannot be used to bypass submit-time validation. A field that has never been interacted with is still validated when the form is submitted.",{"id":816,"title":499,"titles":817,"content":818,"level":95},"\u002Fadvanced\u002Fvalidation-modes#manual-validation",[71],"Validation does not have to come from field events.",{"id":820,"title":821,"titles":822,"content":823,"level":163},"\u002Fadvanced\u002Fvalidation-modes#validate-the-whole-form","Validate the Whole Form",[71,499],"const result = await form.validate() A successful result contains value: const result = await form.validate()\n\nif ('value' in result) {\n  console.log(result.value)\n} A failed result contains issues: const result = await form.validate()\n\nif ('issues' in result) {\n  console.log(result.issues)\n} form.errors is updated to match the complete validation result.",{"id":825,"title":826,"titles":827,"content":828,"level":163},"\u002Fadvanced\u002Fvalidation-modes#validate-a-single-field","Validate a Single Field",[71,499],"const result = await form.validateField('email') validateField() runs the schema against the form values but only updates errors associated with the requested field. Existing errors for other fields are preserved. const result = await form.validateField('email')\n\nif ('issues' in result) {\n  console.log(result.issues)\n} This makes it useful for custom inputs and programmatic field validation.",{"id":830,"title":831,"titles":832,"content":833,"level":95},"\u002Fadvanced\u002Fvalidation-modes#async-validation","Async Validation",[71],"NotForm supports asynchronous Standard Schema validation. For example: const schema = z.object({\n  username: z.string().refine(\n    async (value) => {\n      const response = await fetch(`\u002Fapi\u002Fcheck-username?username=${value}`,)\n\n      const data = await response.json()\n\n      return data.available\n    },\n    {\n      message: 'Username is already taken',\n    },\n  ),\n}) Because validation can be asynchronous, the form exposes: form.isValidating Use it to display loading state: \u003Cp v-if=\"form.isValidating\">\n  Checking username...\n\u003C\u002Fp> isValidating remains active while validation work is still running, including concurrent validation runs.",{"id":835,"title":836,"titles":837,"content":838,"level":95},"\u002Fadvanced\u002Fvalidation-modes#validation-state","Validation State",[71],"Validation produces several pieces of state: form.errors\nform.errorsMap\nform.isValid\nform.isValidating Use errors when you need the complete StandardSchemaV1.Issue[]. Use errorsMap when you need the first message for a field. Use isValid when you only need to know whether the form currently has active errors. Use isValidating when displaying asynchronous validation state.",{"id":840,"title":841,"titles":842,"content":157,"level":95},"\u002Fadvanced\u002Fvalidation-modes#recommended-strategies","Recommended Strategies",[71],{"id":844,"title":845,"titles":846,"content":847,"level":163},"\u002Fadvanced\u002Fvalidation-modes#general-forms","General Forms",[71,841],"A good general-purpose configuration is: const form = useNotForm({\n  schema,\n\n  validateOn: {\n    onBlur: true,\n    onChange: true,\n    onInput: true,\n  },\n\n  validationMode: 'eager',\n\n  onSubmit(values) {\n    console.log(values)\n  },\n})",{"id":849,"title":850,"titles":851,"content":852,"level":163},"\u002Fadvanced\u002Fvalidation-modes#less-intrusive-forms","Less Intrusive Forms",[71,841],"Use lazy validation when you want fewer validation runs while editing: const form = useNotForm({\n  schema,\n\n  validationMode: 'lazy',\n\n  validateOn: {\n    onBlur: true,\n  },\n\n  onSubmit(values) {\n    console.log(values)\n  },\n})",{"id":854,"title":855,"titles":856,"content":857,"level":163},"\u002Fadvanced\u002Fvalidation-modes#async-heavy-fields","Async-Heavy Fields",[71,841],"For expensive asynchronous validators, avoid unnecessarily aggressive input validation: const form = useNotForm({\n  schema,\n\n  validateOn: {\n    onBlur: true,\n    onInput: false,\n  },\n\n  validationMode: 'lazy',\n\n  onSubmit(values) {\n    console.log(values)\n  },\n}) html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .sfNiH, html code.shiki .sfNiH{--shiki-light:#FF5370;--shiki-default:#FF9CAC;--shiki-dark:#FF9CAC}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sHdIc, html code.shiki .sHdIc{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#EEFFFF;--shiki-default-font-style:italic;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}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 .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}",{"id":77,"title":76,"titles":859,"content":860,"level":89},[],"Apply backend validation errors to a NotForm instance and combine them with client-side validation. Client-side validation can catch many problems before a request is sent, but a server can still reject otherwise valid form data. For example, the backend may know that: an email address is already registereda username is already takena value conflicts with another recorda business rule faileda permission or authentication check failed NotForm represents these errors using the same StandardSchemaV1.Issue structure used by client-side validation. This means server errors can live in the same form.errors collection and work with the same field-level error APIs.",{"id":862,"title":863,"titles":864,"content":865,"level":95},"\u002Fadvanced\u002Fserver-errors#the-error-model","The Error Model",[76],"NotForm errors are an array: StandardSchemaV1.Issue[] A field error can look like: {\n  path: ['email'],\n  message: 'This email is already registered.',\n} Nested fields use path segments: {\n  path: ['profile', 'email'],\n  message: 'This email is already registered.',\n} The path is what connects the error to NotField, NotMessage, errorsMap, and getFieldErrors().",{"id":867,"title":868,"titles":869,"content":870,"level":95},"\u002Fadvanced\u002Fserver-errors#applying-server-errors","Applying Server Errors",[76],"Use setError() when applying one issue: form.setError({\n  message: 'This email is already registered.',\n  path: ['email'],\n}) Use setErrors() when the server returns multiple issues: form.setErrors([\n  {\n    message: 'This email is already registered.',\n    path: ['email'],\n  },\n  {\n    message: 'Username is already taken.',\n    path: ['username'],\n  },\n]) These errors immediately become part of: form.errors and: form.errorsMap",{"id":872,"title":873,"titles":874,"content":875,"level":95},"\u002Fadvanced\u002Fserver-errors#basic-submission-example","Basic Submission Example",[76],"A typical submission flow looks like this: const form = useNotForm({\n  schema,\n\n  async onSubmit(values) {\n    const response = await fetch('\u002Fapi\u002Fusers', {\n      body: JSON.stringify(values),\n      headers: {\n        'Content-Type': 'application\u002Fjson',\n      },\n      method: 'POST',\n    })\n\n    if (!response.ok) {\n      const data = await response.json()\n\n      form.setErrors(data.errors)\n\n      return\n    }\n\n    console.log('User created')\n  },\n}) Client-side validation happens before onSubmit is called. If the schema validation succeeds, the request is sent. If the server rejects the request, its issues can then be added to the form.",{"id":877,"title":878,"titles":879,"content":880,"level":95},"\u002Fadvanced\u002Fserver-errors#seterror","setError",[76],"Use setError() for an individual issue: form.setError({\n  message: 'This email is already registered.',\n  path: ['email'],\n}) If an active error already exists for the same normalized path, it is replaced. This is useful when handling one specific backend error: if (response.status === 409) {\n  form.setError({\n    message: 'This email is already registered.',\n    path: ['email'],\n  })\n}",{"id":882,"title":883,"titles":884,"content":885,"level":95},"\u002Fadvanced\u002Fserver-errors#seterrors","setErrors",[76],"Use setErrors() when the backend returns a collection of issues: form.setErrors([\n  {\n    message: 'This email is already registered.',\n    path: ['email'],\n  },\n  {\n    message: 'Username is already taken.',\n    path: ['username'],\n  },\n]) setErrors() replaces the current form.errors collection. This is useful when the server's response represents the complete validation state for the failed request.",{"id":887,"title":888,"titles":889,"content":890,"level":95},"\u002Fadvanced\u002Fserver-errors#server-response-mapping","Server Response Mapping",[76],"Not every API returns StandardSchemaV1.Issue[] directly. For example, your backend might return: {\n  \"errors\": {\n    \"email\": \"This email is already registered.\",\n    \"username\": \"Username is already taken.\"\n  }\n} That response needs to be transformed into NotForm's issue structure: const errors = Object.entries(data.errors).map(([path, message]) => ({\n  message,\n  path: path.split('.'),\n}),)\n\nform.setErrors(errors) For: {\n  \"email\": \"This email is already registered.\",\n  \"user.name\": \"Name is required\"\n} the resulting issues are: [\n  {\n    message: 'This email is already registered.',\n    path: ['email'],\n  },\n  {\n    message: 'Name is required',\n    path: ['user', 'name'],\n  },\n] The important part is that the server error paths correspond to the paths used by the form.",{"id":892,"title":893,"titles":894,"content":895,"level":95},"\u002Fadvanced\u002Fserver-errors#nested-field-errors","Nested Field Errors",[76],"Nested fields use the same path structure as the rest of NotForm. For example: form.setErrors([\n  {\n    message: 'This email is already registered.',\n    path: ['user', 'email'],\n  },\n  {\n    message: 'Name is required.',\n    path: ['user', 'name'],\n  },\n]) The errors can then be accessed using the same paths: form.getFieldErrors('user.email')\nform.errorsMap['user.email'] And displayed through: \u003CNotMessage path=\"user.email\" \u002F>\n\n\u003CNotMessage path=\"user.name\" \u002F>",{"id":897,"title":898,"titles":899,"content":900,"level":95},"\u002Fadvanced\u002Fserver-errors#displaying-server-errors","Displaying Server Errors",[76],"Server errors use the same field components as schema errors. \u003CNotField\n  path=\"email\"\n  v-slot=\"{ events }\"\n>\n  \u003Cinput\n    v-model=\"form.values.email\"\n    v-bind=\"events\"\n  \u002F>\n\n  \u003CNotMessage path=\"email\" \u002F>\n\u003C\u002FNotField> There is no separate server-error component. The field simply displays whatever issues currently exist for its path.",{"id":902,"title":903,"titles":904,"content":905,"level":95},"\u002Fadvanced\u002Fserver-errors#multiple-errors-for-one-field","Multiple Errors for One Field",[76],"A field can have multiple issues. Use getFieldErrors() when you need all of them: const errors = form.getFieldErrors('password')\n\nfor (const error of errors) {\n  console.log(error.message)\n} Or use the field's errors slot prop: \u003CNotField\n  path=\"password\"\n  v-slot=\"{ errors, events }\"\n>\n  \u003Cinput\n    v-model=\"form.values.password\"\n    v-bind=\"events\"\n  \u002F>\n\n  \u003Cul>\n    \u003Cli\n      v-for=\"(error, index) in errors\"\n      :key=\"index\"\n    >\n      {{ error.message }}\n    \u003C\u002Fli>\n  \u003C\u002Ful>\n\u003C\u002FNotField> NotMessage intentionally displays only the first active issue for a field.",{"id":907,"title":908,"titles":909,"content":910,"level":95},"\u002Fadvanced\u002Fserver-errors#global-server-errors","Global Server Errors",[76],"Some failures do not belong to a particular field. Examples include: Rate limit exceeded\nSession expired\nPermission denied\nPayment failed\nUnexpected server error NotForm's issue model is path-oriented, so application-level errors that are not tied to a field should generally be handled separately from field errors. For example: const form = useNotForm({\n  schema,\n\n  async onSubmit(values) {\n    const response = await saveUser(values)\n\n    if (!response.ok) {\n      const data = await response.json()\n\n      if (data.fieldErrors) {\n        form.setErrors(data.fieldErrors)\n      }\n\n      if (data.globalError) {\n        showGlobalError(data.globalError)\n      }\n    }\n  },\n}) This keeps field validation inside NotForm while allowing application-level failures to be rendered elsewhere.",{"id":912,"title":913,"titles":914,"content":915,"level":95},"\u002Fadvanced\u002Fserver-errors#client-and-server-validation-together","Client and Server Validation Together",[76],"A normal submission can involve both kinds of validation: User input\n   ↓\nField validation\n   ↓\nForm submission\n   ↓\nComplete schema validation\n   ↓\nonSubmit()\n   ↓\nServer validation\n   ↓\nServer issues\n   ↓\nform.setErrors()\n   ↓\nField errors displayed The same error collection is used throughout the form. This means the UI does not need to know whether an error came from Zod, Valibot, another Standard Schema validator, or your backend.",{"id":917,"title":918,"titles":919,"content":920,"level":95},"\u002Fadvanced\u002Fserver-errors#server-errors-and-form-state","Server Errors and Form State",[76],"Server errors participate in the normal form state: form.errors\nform.errorsMap\nform.isValid\nform.getFieldErrors('email') For example: form.setError({\n  message: 'Email is already registered.',\n  path: ['email'],\n})\n\nconsole.log(form.errorsMap.email)\nconsole.log(form.isValid.value) Because isValid is derived from the current error collection, adding a server error makes the form invalid until that error is replaced or cleared.",{"id":922,"title":923,"titles":924,"content":157,"level":95},"\u002Fadvanced\u002Fserver-errors#clearing-errors","Clearing Errors",[76],{"id":926,"title":927,"titles":928,"content":929,"level":163},"\u002Fadvanced\u002Fserver-errors#clear-all-errors","Clear All Errors",[76,923],"Use: form.clearErrors() This removes every active error.",{"id":931,"title":932,"titles":933,"content":934,"level":163},"\u002Fadvanced\u002Fserver-errors#replace-all-errors","Replace All Errors",[76,923],"Calling: form.setErrors([]) also results in an empty error collection. The important distinction is that setErrors() replaces the collection with the supplied issues, while clearErrors() is the explicit API for removing all errors.",{"id":936,"title":937,"titles":938,"content":939,"level":95},"\u002Fadvanced\u002Fserver-errors#updating-a-server-error","Updating a Server Error",[76],"Use setError() when the server returns a replacement issue for the same field: form.setError({\n  message: 'The email is unavailable.',\n  path: ['email'],\n}) The existing issue for that path is replaced instead of accumulating another copy.",{"id":941,"title":942,"titles":943,"content":944,"level":95},"\u002Fadvanced\u002Fserver-errors#server-errors-after-resubmission","Server Errors After Resubmission",[76],"A common flow is: const form = useNotForm({\n  schema,\n\n  async onSubmit(values) {\n    const response = await saveUser(values)\n\n    if (!response.ok) {\n      form.setErrors(await response.json())\n      return\n    }\n\n    form.reset()\n  },\n}) On a successful submission, resetting the form can establish a fresh baseline. On a failed submission, keep the current values and apply the backend issues.",{"id":946,"title":128,"titles":947,"content":157,"level":95},"\u002Fadvanced\u002Fserver-errors#demo",[76],{"id":949,"title":950,"titles":951,"content":952,"level":95},"\u002Fadvanced\u002Fserver-errors#recommended-backend-contract","Recommended Backend Contract",[76],"A particularly convenient backend contract is an array of path-aware issues: {\n  \"issues\": [\n    {\n      \"path\": [\"email\"],\n      \"message\": \"This email is already registered.\"\n    },\n    {\n      \"path\": [\n        \"profile\",\n        \"name\"\n      ],\n      \"message\": \"Name is required.\"\n    }\n  ]\n} This maps naturally to: form.setErrors(data.issues) If your backend uses another format, map it at the API boundary rather than teaching your form components about the server's response shape. html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}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 .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sHdIc, html code.shiki .sHdIc{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#EEFFFF;--shiki-default-font-style:italic;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}",{"id":82,"title":81,"titles":954,"content":955,"level":89},[],"Understand Standard Schema integration, input and output types, validation results, and asynchronous validation in NotForm. NotForm does not implement its own validation language. Instead, it works with schemas that implement the Standard Schema interface. This allows the form to use validation libraries such as Zod, Valibot, ArkType, and other Standard Schema-compatible libraries without coupling the form API to one validator.",{"id":957,"title":958,"titles":959,"content":960,"level":95},"\u002Fadvanced\u002Fschema-validation#why-standard-schema","Why Standard Schema?",[81],"A form library needs a consistent way to: validate valuesreceive validation issuessupport asynchronous validationunderstand the schema's input and output types Standard Schema provides that common interface. NotForm only needs to interact with the schema through its Standard Schema contract. That means the rest of the form API stays the same regardless of which validation library you choose.",{"id":962,"title":963,"titles":964,"content":965,"level":95},"\u002Fadvanced\u002Fschema-validation#supported-validators","Supported Validators",[81],"NotForm can work with Standard Schema-compatible validators such as: import { z } from 'zod'\n\nconst schema = z.object({\n  age: z.number().min(18, 'Must be 18 or older'),\n  email: z.email('Invalid email'),\n})\nimport {\n  email,\n  minValue,\n  number,\n  object,\n  string,\n} from 'valibot'\n\nconst schema = object({\n  age: number([minValue(18, 'Must be 18 or older')]),\n  email: string([email('Invalid email')]),\n})\nimport { type } from 'arktype'\n\nconst schema = type({\n  age: 'number>=18',\n  email: 'email',\n}) The NotForm API remains the same regardless of the validator.",{"id":967,"title":968,"titles":969,"content":970,"level":95},"\u002Fadvanced\u002Fschema-validation#defining-a-schema","Defining a Schema",[81],"Create an object schema describing the shape of your form: import { z } from 'zod'\n\nconst schema = z.object({\n  username: z.string().min(\n    3,\n    'Username must be at least 3 characters',\n  ),\n\n  email: z.email('Invalid email address',),\n\n  age: z.number().min(\n    18,\n    'Must be 18 or older',\n  ),\n\n  bio: z.string().optional(),\n}) Pass it directly to useNotForm: const form = useNotForm({\n  schema,\n\n  onSubmit(values) {\n    console.log(values)\n  },\n})",{"id":972,"title":973,"titles":974,"content":975,"level":95},"\u002Fadvanced\u002Fschema-validation#schema-driven-types","Schema-Driven Types",[81],"The schema is the source of truth for the form's types. Given: const schema = z.object({\n  email: z.email(),\n  username: z.string(),\n}) NotForm can infer: form.values.username\nform.values.email and the onSubmit callback receives the schema's validated output: const form = useNotForm({\n  schema,\n\n  onSubmit(values) {\n    values.username\n    values.email\n  },\n}) The same schema also drives field paths and typed APIs such as: form.setValue(...)\nform.validateField(...)\nform.getFieldErrors(...)\nform.reset(...)",{"id":977,"title":978,"titles":979,"content":980,"level":95},"\u002Fadvanced\u002Fschema-validation#input-and-output-types","Input and Output Types",[81],"Standard Schema distinguishes between the data a schema accepts and the data it produces after validation. NotForm preserves that distinction.",{"id":982,"title":983,"titles":984,"content":985,"level":163},"\u002Fadvanced\u002Fschema-validation#input","Input",[81,978],"form.values uses: StandardSchemaV1.InferInput\u003CTSchema> This is the type of data being edited in the form. form.values",{"id":987,"title":988,"titles":989,"content":990,"level":163},"\u002Fadvanced\u002Fschema-validation#output","Output",[81,978],"onSubmit receives: StandardSchemaV1.InferOutput\u003CTSchema> This is the validated result produced by the schema. This distinction matters when the schema transforms data. For example: const schema = z.object({\n  age: z.coerce.number(),\n}) The form can accept an input representation that the schema converts into a number. The submit callback receives the validated schema output: const form = useNotForm({\n  schema,\n\n  onSubmit(values) {\n    \u002F\u002F validated output\n    console.log(values.age)\n  },\n})",{"id":992,"title":993,"titles":994,"content":995,"level":95},"\u002Fadvanced\u002Fschema-validation#initial-values-and-schema-input","Initial Values and Schema Input",[81],"Because form.values represents schema input, initialValues is also based on the schema's input type: const form = useNotForm({\n  schema,\n\n  initialValues: {\n    email: '',\n  },\n\n  onSubmit(values) {\n    \u002F\u002F ...\n  },\n}) The type of initialValues is: DeepPartial\u003CStandardSchemaV1.InferInput\u003CTSchema>> This allows nested initial state to be provided partially.",{"id":997,"title":674,"titles":998,"content":999,"level":95},"\u002Fadvanced\u002Fschema-validation#validation",[81],"When NotForm validates, it executes the schema's Standard Schema validator against the current form values. Conceptually: form.values\n    ↓\nschema\n    ↓\nStandard Schema validate()\n    ↓\n ┌───────────────┐\n │               │\n success       issues\n │               │\n ↓               ↓\nvalue         errors A successful validation produces a value. A failed validation produces issues.",{"id":1001,"title":1002,"titles":1003,"content":1004,"level":95},"\u002Fadvanced\u002Fschema-validation#full-form-validation","Full Form Validation",[81],"Use: const result = await form.validate() A successful result: {\n  value: ...\n} A failed result: {\n  issues: [...]\n} The form error state is updated at the same time. const result = await form.validate()\n\nif ('issues' in result) {\n  console.log(result.issues)\n}\n\nif ('value' in result) {\n  console.log(result.value)\n} A successful validation clears the current error collection. A failed validation replaces it with the new issues.",{"id":1006,"title":1007,"titles":1008,"content":1009,"level":95},"\u002Fadvanced\u002Fschema-validation#field-validation","Field Validation",[81],"You can validate one field: const result = await form.validateField('email') validateField() still validates using the complete schema. The important difference is what happens to the errors: errors for the requested path are replacederrors for other paths remain untouched This allows one field to be revalidated without resetting the validation state of the rest of the form. await form.validateField('email') is therefore different from: await form.validate() The first updates one field's error state; the second replaces the complete error collection.",{"id":1011,"title":1012,"titles":1013,"content":1014,"level":95},"\u002Fadvanced\u002Fschema-validation#validation-issues","Validation Issues",[81],"NotForm stores validation failures as: StandardSchemaV1.Issue[] An issue can contain a path and message: {\n  path: ['email'],\n  message: 'Invalid email address',\n} Nested paths use multiple segments: {\n  path: ['profile', 'email'],\n  message: 'Invalid email address',\n} NotForm uses these paths for: form.getFieldErrors('profile.email')\nform.errorsMap['profile.email'] and components such as: \u003CNotMessage path=\"profile.email\" \u002F>",{"id":1016,"title":1017,"titles":1018,"content":1019,"level":95},"\u002Fadvanced\u002Fschema-validation#multiple-issues","Multiple Issues",[81],"A schema can return multiple issues for the same field. For example: const schema = z.object({\n  password: z\n    .string()\n    .min(8, 'Must be at least 8 characters')\n    .regex(\n      \u002F[A-Z]\u002F,\n      'Must contain an uppercase letter',\n    )\n    .regex(\n      \u002F[0-9]\u002F,\n      'Must contain a number',\n    ),\n}) The raw issues are available through: form.errors or: form.getFieldErrors('password') For simple UI rendering, form.errorsMap.password contains the first message for the field.",{"id":1021,"title":1022,"titles":1023,"content":1024,"level":95},"\u002Fadvanced\u002Fschema-validation#custom-error-messages","Custom Error Messages",[81],"NotForm does not rewrite schema messages. The validation library determines the message: const schema = z.object({\n  password: z.string()\n    .min(8, 'Password must be at least 8 characters')\n    .regex(\n      \u002F[A-Z]\u002F,\n      'Must contain an uppercase letter',\n    )\n    .regex(\n      \u002F[0-9]\u002F,\n      'Must contain at least one number',\n    ),\n}) Those messages become the message properties of the resulting issues. This means validation rules and validation copy remain inside your schema.",{"id":1026,"title":831,"titles":1027,"content":1028,"level":95},"\u002Fadvanced\u002Fschema-validation#async-validation",[81],"Standard Schema validation can be asynchronous. For example, checking username availability: const schema = z.object({\n  username: z.string().refine(\n    async (value) => {\n      const response = await fetch(`\u002Fapi\u002Fcheck-username?username=${value}`,)\n\n      const data = await response.json()\n\n      return data.available\n    },\n    {\n      message: 'Username is already taken',\n    },\n  ),\n}) Use the schema normally: const form = useNotForm({\n  schema,\n\n  onSubmit(values) {\n    console.log(values)\n  },\n}) NotForm awaits the schema's validation result. While validation is running: form.isValidating is true. This makes it possible to show asynchronous feedback: \u003Cp v-if=\"form.isValidating\">\n  Checking username...\n\u003C\u002Fp>",{"id":1030,"title":1031,"titles":1032,"content":1033,"level":95},"\u002Fadvanced\u002Fschema-validation#async-validation-and-triggers","Async Validation and Triggers",[81],"Async validation works with the same validateOn configuration as synchronous validation. For example: const form = useNotForm({\n  schema,\n\n  validateOn: {\n    onBlur: true,\n    onInput: false,\n  },\n\n  validationMode: 'lazy',\n\n  onSubmit(values) {\n    console.log(values)\n  },\n}) Now the expensive asynchronous validator does not run on every input interaction. See Validation Modes for controlling these triggers and modes.",{"id":1035,"title":1036,"titles":1037,"content":1038,"level":95},"\u002Fadvanced\u002Fschema-validation#schema-transformations","Schema Transformations",[81],"One of the advantages of keeping input and output types separate is that schemas can transform or normalize data. For example: const schema = z.object({\n  name: z.string().transform(value => value.trim(),),\n}) The form edits the schema input: form.values.name while successful submission receives the schema output: onSubmit(values) {\n  \u002F\u002F transformed value\n  console.log(values.name)\n} The validation layer therefore becomes the boundary between editable form state and validated application data.",{"id":1040,"title":1041,"titles":1042,"content":1043,"level":95},"\u002Fadvanced\u002Fschema-validation#schema-as-a-ref-or-getter","Schema as a Ref or Getter",[81],"schema accepts a MaybeRefOrGetter, so the schema can be resolved dynamically. For example: const schema = computed(() => {\n  return isCompany.value\n    ? companySchema\n    : personSchema\n})\n\nconst form = useNotForm({\n  schema,\n\n  onSubmit(values) {\n    console.log(values)\n  },\n}) NotForm resolves the current schema when validation runs. This allows validation rules to depend on reactive application state.",{"id":1045,"title":1046,"titles":1047,"content":1048,"level":95},"\u002Fadvanced\u002Fschema-validation#validation-does-not-mutate-your-schema","Validation Does Not Mutate Your Schema",[81],"NotForm delegates validation to the supplied schema. The form owns: form.values\nform.errors\nform.isValid\nform.isValidating The schema owns: validation rules\ntransformations\nissue messages\ninput\u002Foutput validation Keeping those responsibilities separate means your schema can be reused outside the form.",{"id":1050,"title":1051,"titles":1052,"content":1053,"level":95},"\u002Fadvanced\u002Fschema-validation#server-validation","Server Validation",[81],"A server can still reject data after client validation succeeds. Those backend errors can be represented with the same StandardSchemaV1.Issue structure: form.setErrors([\n  {\n    message: 'This email is already registered.',\n    path: ['email'],\n  },\n]) This allows client and server errors to share the same form error state. See Server Errors for the complete server-error workflow.",{"id":1055,"title":1056,"titles":1057,"content":1058,"level":95},"\u002Fadvanced\u002Fschema-validation#choosing-a-validator","Choosing a Validator",[81],"NotForm does not require a particular validator. Choose the Standard Schema-compatible library that best fits your project. For example: Zod for a broadly adopted schema APIValibot for a lightweight modular approachArkType for type-oriented schemas Regardless of the validator, the NotForm API remains the same: const form = useNotForm({\n  schema,\n\n  onSubmit(values) {\n    console.log(values)\n  },\n}) html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}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 .sHdIc, html code.shiki .sHdIc{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#EEFFFF;--shiki-default-font-style:italic;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .sfNiH, html code.shiki .sfNiH{--shiki-light:#FF5370;--shiki-default:#FF9CAC;--shiki-dark:#FF9CAC}",21,{"left":1061,"top":1061,"width":1062,"height":1062,"rotate":1061,"vFlip":32,"hFlip":32,"body":1063},0,24,"\u003Cg fill=\"none\">\u003C!--field 1-->\n  \u003Crect x=\"0.5\" y=\"0.5\" width=\"23\" height=\"3\" rx=\"0.3\" stroke=\"currentColor\" stroke-opacity=\"0.5\" stroke-width=\"0.3\"\u002F>\n\u003C!--field 2 — active-->\n  \u003Crect x=\"0.5\" y=\"4.3\" width=\"23\" height=\"3\" rx=\"0.3\" fill=\"currentColor\" fill-opacity=\"0.12\" stroke=\"currentColor\" stroke-opacity=\"0.75\" stroke-width=\"0.3\"\u002F>\n  \u003Crect x=\"1\" y=\"5.7\" width=\"8\" height=\"0.3\" rx=\"0.2\" fill=\"currentColor\" fill-opacity=\"0.5\"\u002F>\n\u003C!--field 3-->\n  \u003Crect x=\"0.5\" y=\"8.6\" width=\"23\" height=\"3\" rx=\"0.3\" stroke=\"currentColor\" stroke-opacity=\"0.5\" stroke-width=\"0.3\"\u002F>\n\u003C!--button-->\n  \u003Crect x=\"0.5\" y=\"12.9\" width=\"9.9\" height=\"3\" rx=\"0.3\" fill=\"currentColor\" fill-opacity=\"0.2\" stroke=\"currentColor\" stroke-width=\"0.2\"\u002F>\n  \u003Crect x=\"2.2\" y=\"14.3\" width=\"5.5\" height=\"0.4\" rx=\"0.2\" fill=\"currentColor\" fill-opacity=\"0.85\"\u002F>\u003C\u002Fg>",{"left":1061,"top":1061,"width":1062,"height":1062,"rotate":1061,"vFlip":32,"hFlip":32,"body":1065},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M3 10a7 7 0 1 0 14 0a7 7 0 1 0-14 0m18 11l-6-6\"\u002F>",{"left":1061,"top":1061,"width":1062,"height":1062,"rotate":1061,"vFlip":32,"hFlip":32,"body":1067},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M12 3h.393a7.5 7.5 0 0 0 7.92 12.446A9 9 0 1 1 12 2.992z\"\u002F>",{"left":1061,"top":1061,"width":1062,"height":1062,"rotate":1061,"vFlip":32,"hFlip":32,"body":1069},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M8 12a4 4 0 1 0 8 0a4 4 0 1 0-8 0m-5 0h1m8-9v1m8 8h1m-9 8v1M5.6 5.6l.7.7m12.1-.7l-.7.7m0 11.4l.7.7m-12.1-.7l-.7.7\"\u002F>",{"left":1061,"top":1061,"width":1062,"height":1062,"rotate":1061,"vFlip":32,"hFlip":32,"body":1071},"\u003Cpath fill=\"currentColor\" d=\"M12 .297c-6.63 0-12 5.373-12 12c0 5.303 3.438 9.8 8.205 11.385c.6.113.82-.258.82-.577c0-.285-.01-1.04-.015-2.04c-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729c1.205.084 1.838 1.236 1.838 1.236c1.07 1.835 2.809 1.305 3.495.998c.108-.776.417-1.305.76-1.605c-2.665-.3-5.466-1.332-5.466-5.93c0-1.31.465-2.38 1.235-3.22c-.135-.303-.54-1.523.105-3.176c0 0 1.005-.322 3.3 1.23c.96-.267 1.98-.399 3-.405c1.02.006 2.04.138 3 .405c2.28-1.552 3.285-1.23 3.285-1.23c.645 1.653.24 2.873.12 3.176c.765.84 1.23 1.91 1.23 3.22c0 4.61-2.805 5.625-5.475 5.92c.42.36.81 1.096.81 2.22c0 1.606-.015 2.896-.015 3.286c0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12\"\u002F>",{"left":1061,"top":1061,"width":1062,"height":1062,"rotate":1061,"vFlip":32,"hFlip":32,"body":1073},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M19.5 12.572L12 20l-7.5-7.428A5 5 0 1 1 12 6.006a5 5 0 1 1 7.5 6.572\"\u002F>",{"left":1061,"top":1061,"width":1062,"height":1062,"rotate":1061,"vFlip":32,"hFlip":32,"body":1075},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M4 8h16M4 16h16\"\u002F>",{"left":1061,"top":1061,"width":1062,"height":1062,"rotate":1061,"vFlip":32,"hFlip":32,"body":1077},"\u003Cg fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\">\u003Cpath d=\"M4 13a8 8 0 0 1 7 7a6 6 0 0 0 3-5a9 9 0 0 0 6-8a3 3 0 0 0-3-3a9 9 0 0 0-8 6a6 6 0 0 0-5 3\"\u002F>\u003Cpath d=\"M7 14a6 6 0 0 0-3 6a6 6 0 0 0 6-3m4-8a1 1 0 1 0 2 0a1 1 0 1 0-2 0\"\u002F>\u003C\u002Fg>",{"left":1061,"top":1061,"width":1062,"height":1062,"rotate":1061,"vFlip":32,"hFlip":32,"body":1079},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"m12 3l8 4.5v9L12 21l-8-4.5v-9zm0 9l8-4.5M12 12v9m0-9L4 7.5m12-2.25l-8 4.5\"\u002F>",{"left":1061,"top":1061,"width":1062,"height":1062,"rotate":1061,"vFlip":32,"hFlip":32,"body":1081},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M13 3v7h6l-8 11v-7H5z\"\u002F>",{"left":1061,"top":1061,"width":1062,"height":1062,"rotate":1061,"vFlip":32,"hFlip":32,"body":1083},"\u003Cpath fill=\"currentColor\" d=\"M13.464 19.83h8.922c.283 0 .562-.073.807-.21a1.6 1.6 0 0 0 .591-.574a1.53 1.53 0 0 0 .216-.783a1.53 1.53 0 0 0-.217-.782L17.792 7.414a1.6 1.6 0 0 0-.591-.573a1.65 1.65 0 0 0-.807-.21c-.283 0-.562.073-.807.21a1.6 1.6 0 0 0-.59.573L13.463 9.99L10.47 4.953a1.6 1.6 0 0 0-.591-.573a1.65 1.65 0 0 0-.807-.21c-.284 0-.562.073-.807.21a1.6 1.6 0 0 0-.591.573L.216 17.481a1.53 1.53 0 0 0-.217.782c0 .275.074.545.216.783a1.6 1.6 0 0 0 .59.574c.246.137.525.21.808.21h5.6c2.22 0 3.856-.946 4.982-2.79l2.733-4.593l1.464-2.457l4.395 7.382h-5.859Zm-6.341-2.46l-3.908-.002l5.858-9.842l2.923 4.921l-1.957 3.29c-.748 1.196-1.597 1.632-2.916 1.632\"\u002F>",{"left":1061,"top":1061,"width":1062,"height":1062,"rotate":1061,"vFlip":32,"hFlip":32,"body":1085},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M6 6a2 2 0 0 1 2-2h8a2 2 0 0 1 2 2v4a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2zm6-4v2m-3 8v9m6-9v9M5 16l4-2m6 0l4 2M9 18h6M10 8v.01M14 8v.01\"\u002F>",{"left":1061,"top":1061,"width":1062,"height":1062,"rotate":1061,"vFlip":32,"hFlip":32,"body":1087},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"m7 8l-4 4l4 4m10-8l4 4l-4 4M14 4l-4 16\"\u002F>",{"left":1061,"top":1061,"width":1062,"height":1062,"rotate":1061,"vFlip":32,"hFlip":32,"body":1089},"\u003Cg fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\">\u003Cpath d=\"M4 6.667A2.667 2.667 0 0 1 6.667 4h10.666A2.667 2.667 0 0 1 20 6.667v10.666A2.667 2.667 0 0 1 17.333 20H6.667A2.667 2.667 0 0 1 4 17.333z\"\u002F>\u003Cpath d=\"M9 15.5v.25c0 .69.56 1.25 1.25 1.25a1.38 1.38 0 0 0 1.374-1.244l.752-7.512A1.38 1.38 0 0 1 13.75 7c.69 0 1.25.56 1.25 1.25v.25M9 12h6\"\u002F>\u003C\u002Fg>",{"left":1061,"top":1061,"width":1062,"height":1062,"rotate":1061,"vFlip":32,"hFlip":32,"body":1091},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"m6 9l6 6l6-6\"\u002F>",{"left":1061,"top":1061,"width":1062,"height":1062,"rotate":1061,"vFlip":32,"hFlip":32,"body":1093},"\u003Cg fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\">\u003Cpath d=\"M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 0 0 2.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 0 0 1.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 0 0-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 0 0-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 0 0-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 0 0-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 0 0 1.066-2.573c-.94-1.543.826-3.31 2.37-2.37c1 .608 2.296.07 2.572-1.065\"\u002F>\u003Cpath d=\"M9 12a3 3 0 1 0 6 0a3 3 0 0 0-6 0\"\u002F>\u003C\u002Fg>",{"left":1061,"top":1061,"width":1062,"height":1062,"rotate":1061,"vFlip":32,"hFlip":32,"body":1095},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M3 7a3 3 0 0 1 3-3h12a3 3 0 0 1 3 3v2a3 3 0 0 1-3 3H6a3 3 0 0 1-3-3zm0 8a3 3 0 0 1 3-3h12a3 3 0 0 1 3 3v2a3 3 0 0 1-3 3H6a3 3 0 0 1-3-3zm4-7v.01M7 16v.01\"\u002F>",{"left":1061,"top":1061,"width":1062,"height":1062,"rotate":1061,"vFlip":32,"hFlip":32,"body":1097},"\u003Cg fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\">\u003Cpath d=\"M12 3a12 12 0 0 0 8.5 3A12 12 0 0 1 12 21A12 12 0 0 1 3.5 6A12 12 0 0 0 12 3\"\u002F>\u003Cpath d=\"M11 11a1 1 0 1 0 2 0a1 1 0 1 0-2 0m1 1v2.5\"\u002F>\u003C\u002Fg>",{"id":1099,"title":13,"body":1100,"description":1434,"extension":1435,"meta":1436,"navigation":1437,"path":14,"seo":1438,"stem":15,"__hash__":1439},"docs\u002F1.getting-started\u002F2.installation.md",{"type":1101,"value":1102,"toc":1428},"minimark",[1103,1107,1114,1118,1121,1149,1152,1231,1241,1244,1247,1254,1392,1395,1400,1403,1409,1412,1415,1418,1424],[1104,1105,1106],"p",{},"NotForm is distributed as an npm package and can be used directly in any Vue 3 application.",[1104,1108,1109,1110,1113],{},"If you are using Nuxt, we recommend using the official ",[1111,1112,23],"a",{"href":24}," instead. The Nuxt integration handles the framework-specific setup for you and provides a zero-config experience.",[1115,1116,106],"h2",{"id":1117},"install-the-package",[1104,1119,1120],{},"Install NotForm using your preferred package manager.",[1104,1122,1123,1124,1130,1131,1136,1137,1142,1143,1148],{},"NotForm uses ",[1111,1125,1129],{"href":1126,"rel":1127},"https:\u002F\u002Fstandardschema.dev",[1128],"nofollow","Standard Schema"," for validation, so you will also need a compatible validation library. Popular options include ",[1111,1132,1135],{"href":1133,"rel":1134},"https:\u002F\u002Fzod.dev",[1128],"Zod",", ",[1111,1138,1141],{"href":1139,"rel":1140},"https:\u002F\u002Fvalibot.dev",[1128],"Valibot",", and ",[1111,1144,1147],{"href":1145,"rel":1146},"https:\u002F\u002Farktype.io",[1128],"ArkType",".",[1104,1150,1151],{},"Choose the validation library you want to use and install it alongside NotForm.",[1153,1154,1155,1182,1198,1215],"code-group",{},[1156,1157,1162],"pre",{"className":1158,"code":1159,"filename":1160,"language":1161,"meta":157,"style":157},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","pnpm add notform zod\n","pnpm","bash",[1163,1164,1165],"code",{"__ignoreMap":157},[1166,1167,1169,1172,1176,1179],"span",{"class":1168,"line":89},"line",[1166,1170,1160],{"class":1171},"sBMFI",[1166,1173,1175],{"class":1174},"sfazB"," add",[1166,1177,1178],{"class":1174}," notform",[1166,1180,1181],{"class":1174}," zod\n",[1156,1183,1186],{"className":1158,"code":1184,"filename":1185,"language":1161,"meta":157,"style":157},"yarn add notform zod\n","yarn",[1163,1187,1188],{"__ignoreMap":157},[1166,1189,1190,1192,1194,1196],{"class":1168,"line":89},[1166,1191,1185],{"class":1171},[1166,1193,1175],{"class":1174},[1166,1195,1178],{"class":1174},[1166,1197,1181],{"class":1174},[1156,1199,1202],{"className":1158,"code":1200,"filename":1201,"language":1161,"meta":157,"style":157},"npm install notform zod\n","npm",[1163,1203,1204],{"__ignoreMap":157},[1166,1205,1206,1208,1211,1213],{"class":1168,"line":89},[1166,1207,1201],{"class":1171},[1166,1209,1210],{"class":1174}," install",[1166,1212,1178],{"class":1174},[1166,1214,1181],{"class":1174},[1156,1216,1219],{"className":1158,"code":1217,"filename":1218,"language":1161,"meta":157,"style":157},"bun add notform zod\n","bun",[1163,1220,1221],{"__ignoreMap":157},[1166,1222,1223,1225,1227,1229],{"class":1168,"line":89},[1166,1224,1218],{"class":1171},[1166,1226,1175],{"class":1174},[1166,1228,1178],{"class":1174},[1166,1230,1181],{"class":1174},[1232,1233,1234],"note",{},[1104,1235,1236,1237,1240],{},"You can replace ",[1163,1238,1239],{},"zod"," with another Standard Schema-compatible validation library if you prefer.",[1115,1242,111],{"id":1243},"vue-and-vite",[1104,1245,1246],{},"NotForm is designed for Vue 3 and works with standard Vue applications without requiring a special build step or application-level configuration.",[1104,1248,1249,1250,1253],{},"Once installed, you can import the components, composables, and utilities you need directly from ",[1163,1251,1252],{},"notform",":",[1156,1255,1260],{"className":1256,"code":1257,"filename":1258,"language":1259,"meta":157,"style":157},"language-vue shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","\u003Cscript setup lang=\"ts\">\nimport { NotField, NotForm, NotMessage } from 'notform'\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003CNotForm>\n    \u003C!-- form fields -->\n  \u003C\u002FNotForm>\n\u003C\u002Ftemplate>\n","App.vue","vue",[1163,1261,1262,1293,1331,1340,1346,1356,1366,1373,1383],{"__ignoreMap":157},[1166,1263,1264,1268,1272,1276,1279,1282,1285,1288,1290],{"class":1168,"line":89},[1166,1265,1267],{"class":1266},"sMK4o","\u003C",[1166,1269,1271],{"class":1270},"swJcz","script",[1166,1273,1275],{"class":1274},"spNyl"," setup",[1166,1277,1278],{"class":1274}," lang",[1166,1280,1281],{"class":1266},"=",[1166,1283,1284],{"class":1266},"\"",[1166,1286,1287],{"class":1174},"ts",[1166,1289,1284],{"class":1266},[1166,1291,1292],{"class":1266},">\n",[1166,1294,1295,1299,1302,1306,1309,1312,1314,1317,1320,1323,1326,1328],{"class":1168,"line":95},[1166,1296,1298],{"class":1297},"s7zQu","import",[1166,1300,1301],{"class":1266}," {",[1166,1303,1305],{"class":1304},"sTEyZ"," NotField",[1166,1307,1308],{"class":1266},",",[1166,1310,1311],{"class":1304}," NotForm",[1166,1313,1308],{"class":1266},[1166,1315,1316],{"class":1304}," NotMessage",[1166,1318,1319],{"class":1266}," }",[1166,1321,1322],{"class":1297}," from",[1166,1324,1325],{"class":1266}," '",[1166,1327,1252],{"class":1174},[1166,1329,1330],{"class":1266},"'\n",[1166,1332,1333,1336,1338],{"class":1168,"line":163},[1166,1334,1335],{"class":1266},"\u003C\u002F",[1166,1337,1271],{"class":1270},[1166,1339,1292],{"class":1266},[1166,1341,1342],{"class":1168,"line":549},[1166,1343,1345],{"emptyLinePlaceholder":1344},true,"\n",[1166,1347,1349,1351,1354],{"class":1168,"line":1348},5,[1166,1350,1267],{"class":1266},[1166,1352,1353],{"class":1270},"template",[1166,1355,1292],{"class":1266},[1166,1357,1359,1362,1364],{"class":1168,"line":1358},6,[1166,1360,1361],{"class":1266},"  \u003C",[1166,1363,39],{"class":1270},[1166,1365,1292],{"class":1266},[1166,1367,1369],{"class":1168,"line":1368},7,[1166,1370,1372],{"class":1371},"sHwdD","    \u003C!-- form fields -->\n",[1166,1374,1376,1379,1381],{"class":1168,"line":1375},8,[1166,1377,1378],{"class":1266},"  \u003C\u002F",[1166,1380,39],{"class":1270},[1166,1382,1292],{"class":1266},[1166,1384,1386,1388,1390],{"class":1168,"line":1385},9,[1166,1387,1335],{"class":1266},[1166,1389,1353],{"class":1270},[1166,1391,1292],{"class":1266},[1104,1393,1394],{},"NotForm follows the normal Vue component model, so there is no global registration step required. Import only the pieces you use in your application.",[1104,1396,1397,1398,1148],{},"The exact form structure and available components are covered in the ",[1111,1399,18],{"href":19},[1115,1401,116],{"id":1402},"nuxt",[1104,1404,1405,1406,1408],{},"For Nuxt applications, use the ",[1111,1407,23],{"href":24}," rather than manually configuring NotForm.",[1104,1410,1411],{},"The module integrates NotForm with Nuxt and takes care of the framework-specific setup, allowing you to start using NotForm without adding that configuration yourself.",[1115,1413,98],{"id":1414},"next-steps",[1104,1416,1417],{},"NotForm is now ready to use in your project.",[1104,1419,1420,1421,1423],{},"Continue to the ",[1111,1422,18],{"href":19}," to create your first form and learn how NotForm's components, fields, validation, and Standard Schema integration work together.",[1425,1426,1427],"style",{},"html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}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 .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}",{"title":157,"searchDepth":89,"depth":95,"links":1429},[1430,1431,1432,1433],{"id":1117,"depth":95,"text":106},{"id":1243,"depth":95,"text":111},{"id":1402,"depth":95,"text":116},{"id":1414,"depth":95,"text":98},"Add NotForm to your Vue 3 or Vite project.","md",{},{"icon":16},{"title":13,"description":1434},"i61pWdNBpJlaxayc7YLYLuh-y-7G49aQd0EwfoYFPPM",[1441,1443],{"title":10,"path":6,"stem":7,"description":1442,"icon":11,"children":-1},"Headless, schema-agnostic form management for Vue 3 and Nuxt.",{"title":18,"path":19,"stem":20,"description":1444,"icon":21,"children":-1},"Build a fully typed login form with validation in minutes.",{"left":1061,"top":1061,"width":1062,"height":1062,"rotate":1061,"vFlip":32,"hFlip":32,"body":1446},"\u003Cg fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\">\u003Cpath d=\"M7 9.667A2.667 2.667 0 0 1 9.667 7h8.666A2.667 2.667 0 0 1 21 9.667v8.666A2.667 2.667 0 0 1 18.333 21H9.667A2.667 2.667 0 0 1 7 18.333z\"\u002F>\u003Cpath d=\"M4.012 16.737A2 2 0 0 1 3 15V5c0-1.1.9-2 2-2h10c.75 0 1.158.385 1.5 1\"\u002F>\u003C\u002Fg>",{"left":1061,"top":1061,"width":1062,"height":1062,"rotate":1061,"vFlip":32,"hFlip":32,"body":1448},"\u003Cg fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\">\u003Cpath d=\"M7 7H6a2 2 0 0 0-2 2v9a2 2 0 0 0 2 2h9a2 2 0 0 0 2-2v-1\"\u002F>\u003Cpath d=\"M20.385 6.585a2.1 2.1 0 0 0-2.97-2.97L9 12v3h3zM16 5l3 3\"\u002F>\u003C\u002Fg>",{"left":1061,"top":1061,"width":1062,"height":1062,"rotate":1061,"vFlip":32,"hFlip":32,"body":1450},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"m12 17.75l-6.172 3.245l1.179-6.873l-5-4.867l6.9-1l3.086-6.253l3.086 6.253l6.9 1l-5 4.867l1.179 6.873z\"\u002F>",{"left":1061,"top":1061,"width":1062,"height":1062,"rotate":1061,"vFlip":32,"hFlip":32,"body":1452},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M12 6H6a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2v-6m-7 1l9-9m-5 0h5v5\"\u002F>",{"left":1061,"top":1061,"width":1062,"height":1062,"rotate":1061,"vFlip":32,"hFlip":32,"body":1454},"\u003Cg fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\">\u003Cpath d=\"M12 9h.01M11 12h1v4h1\"\u002F>\u003Cpath d=\"M12 3c7.2 0 9 1.8 9 9s-1.8 9-9 9s-9-1.8-9-9s1.8-9 9-9\"\u002F>\u003C\u002Fg>",{"left":1061,"top":1061,"width":1062,"height":1062,"rotate":1061,"vFlip":32,"hFlip":32,"body":1456},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M5 9h14M5 15h14M11 4L7 20M17 4l-4 16\"\u002F>",{"left":1061,"top":1061,"width":1458,"height":1458,"rotate":1061,"vFlip":32,"hFlip":32,"body":1459},32,"\u003Cpath fill=\"#f9ad00\" d=\"M30 10.75h-8.749V2H30Zm-9.626 0h-8.75V2h8.75Zm-9.625 0H2V2h8.749ZM30 20.375h-8.749v-8.75H30Z\"\u002F>\u003Cpath fill=\"#fff\" d=\"M20.374 20.375h-8.75v-8.75h8.75Zm0 9.625h-8.75v-8.75h8.75ZM30 30h-8.749v-8.75H30Zm-19.251 0H2v-8.75h8.749Z\"\u002F>",{"left":1061,"top":1061,"width":1458,"height":1458,"rotate":1061,"vFlip":32,"hFlip":32,"body":1461},"\u003Cpath fill=\"#2188b6\" d=\"M28.208 24.409a10.5 10.5 0 0 0-3.959 1.822a23.7 23.7 0 0 1-5.835 2.642a1.63 1.63 0 0 1-.983.55a62 62 0 0 1-6.447.577c-1.163.009-1.876-.3-2.074-.776a1.573 1.573 0 0 1 .866-2.074a4 4 0 0 1-.514-.379c-.171-.171-.352-.514-.406-.388c-.225.55-.343 1.894-.947 2.5c-.83.839-2.4.559-3.328.072c-1.019-.541.072-1.813.072-1.813a.73.73 0 0 1-.992-.343a4.85 4.85 0 0 1-.667-2.949a5.37 5.37 0 0 1 1.749-2.895a9.3 9.3 0 0 1 .658-4.4a10.45 10.45 0 0 1 3.165-3.661S6.628 10.747 7.35 8.817c.469-1.262.658-1.253.812-1.308a3.6 3.6 0 0 0 1.452-.857a5.27 5.27 0 0 1 4.41-1.7S15.2 1.4 16.277 2.09a18.4 18.4 0 0 1 1.533 2.886s1.281-.748 1.425-.469a11.33 11.33 0 0 1 .523 6.132a14 14 0 0 1-2.6 5.411c-.135.225 1.551.938 2.615 3.887c.983 2.7.108 4.96.262 5.212c.027.045.036.063.036.063s1.127.09 3.391-1.308a8.5 8.5 0 0 1 4.277-1.604a1.081 1.081 0 0 1 .469 2.11Z\"\u002F>",{"left":1061,"top":1061,"width":1458,"height":1458,"rotate":1061,"vFlip":32,"hFlip":32,"body":1463},"\u003Cpath fill=\"#c12127\" d=\"M2 2h28v28H2\"\u002F>\u003Cpath fill=\"#fff\" d=\"M7.25 7.25h17.5v17.5h-3.5v-14H16v14H7.25\"\u002F>",{"left":1061,"top":1061,"width":1458,"height":1458,"rotate":1061,"vFlip":32,"hFlip":32,"body":1465},"\u003Cpath fill=\"#fbf0df\" d=\"M29 17c0 5.65-5.82 10.23-13 10.23S3 22.61 3 17c0-3.5 2.24-6.6 5.66-8.44S14.21 4.81 16 4.81s3.32 1.54 7.34 3.71C26.76 10.36 29 13.46 29 17\"\u002F>\u003Cpath fill=\"none\" stroke=\"#000\" d=\"M16 27.65c7.32 0 13.46-4.65 13.46-10.65c0-3.72-2.37-7-5.89-8.85c-1.39-.75-2.46-1.41-3.37-2l-1.13-.69A6.14 6.14 0 0 0 16 4.35a6.9 6.9 0 0 0-3.3 1.23c-.42.24-.86.51-1.32.8c-.87.54-1.83 1.13-3 1.73C4.91 10 2.54 13.24 2.54 17c0 6 6.14 10.65 13.46 10.65Z\"\u002F>\u003Cellipse cx=\"21.65\" cy=\"18.62\" fill=\"#febbd0\" rx=\"2.17\" ry=\"1.28\"\u002F>\u003Cellipse cx=\"10.41\" cy=\"18.62\" fill=\"#febbd0\" rx=\"2.17\" ry=\"1.28\"\u002F>\u003Cpath fill-rule=\"evenodd\" d=\"M11.43 18.11a2 2 0 1 0-2-2.05a2.05 2.05 0 0 0 2 2.05m9.2 0a2 2 0 1 0-2-2.05a2 2 0 0 0 2 2.05\"\u002F>\u003Cpath fill=\"#fff\" fill-rule=\"evenodd\" d=\"M10.79 16.19a.77.77 0 1 0-.76-.77a.76.76 0 0 0 .76.77m9.2 0a.77.77 0 1 0 0-1.53a.77.77 0 0 0 0 1.53\"\u002F>\u003Cpath fill=\"#b71422\" stroke=\"#000\" stroke-width=\".75\" d=\"M18.62 19.67a3.3 3.3 0 0 1-1.09 1.75a2.48 2.48 0 0 1-1.5.69a2.53 2.53 0 0 1-1.5-.69a3.28 3.28 0 0 1-1.08-1.75a.26.26 0 0 1 .29-.3h4.58a.27.27 0 0 1 .3.3Z\"\u002F>\u003Cpath fill=\"#ccbea7\" fill-rule=\"evenodd\" d=\"M14.93 5.75a6.1 6.1 0 0 1-2.09 4.62c-.1.09 0 .27.11.22c1.25-.49 2.94-1.94 2.23-4.88c-.03-.15-.25-.11-.25.04m.85 0a6 6 0 0 1 .57 5c0 .13.12.24.21.13c.83-1 1.54-3.11-.59-5.31c-.1-.11-.27.04-.19.17Zm1-.06a6.1 6.1 0 0 1 2.53 4.38c0 .14.21.17.24 0c.34-1.3.15-3.51-2.66-4.66c-.12-.02-.21.18-.09.27ZM9.94 9.55a6.27 6.27 0 0 0 3.89-3.33c.07-.13.28-.08.25.07c-.64 3-2.79 3.59-4.13 3.51c-.14-.01-.14-.21-.01-.25\"\u002F>",{"left":1061,"top":1061,"width":1458,"height":1458,"rotate":1061,"vFlip":32,"hFlip":32,"body":1467},"\u003Cpath fill=\"#41b883\" d=\"M24.4 3.925H30l-14 24.15L2 3.925h10.71l3.29 5.6l3.22-5.6Z\"\u002F>\u003Cpath fill=\"#41b883\" d=\"m2 3.925l14 24.15l14-24.15h-5.6L16 18.415L7.53 3.925Z\"\u002F>\u003Cpath fill=\"#35495e\" d=\"M7.53 3.925L16 18.485l8.4-14.56h-5.18L16 9.525l-3.29-5.6Z\"\u002F>",1787852223798]