[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"navigation":3,"url-settings":86,"blog-\u002Fblog\u002Freact-form-validation-informed":663,"blog-author-\u002Fblog\u002Freact-form-validation-informed":1082,"i-material-symbols:arrow-back-rounded":1094},{"id":4,"extension":5,"footer":6,"header":73,"meta":83,"stem":84,"__hash__":85},"navigation\u002Fdata\u002Fshared\u002Fnavigation.yml","yml",{"brand":7,"columns":13,"legal":63},{"name":8,"tagline":9,"downloadCta":10},"Pieces","The memory layer for modern work.",{"label":11,"href":12},"All downloads","\u002Fdownloads",[14,26,39,51],{"title":15,"links":16},"Product",[17,20,23],{"label":18,"href":19},"Pieces Desktop","\u002F",{"label":21,"href":22},"Pieces Enterprise","\u002Fenterprise",{"label":24,"href":25},"Pieces MCP","\u002Fmcp",{"title":27,"links":28},"Resources",[29,33,36],{"label":30,"href":31,"external":32},"Documentation","url:docs.home",true,{"label":34,"href":35},"Blog","\u002Fblog",{"label":37,"href":38,"external":32},"GitHub","url:github.org",{"title":40,"links":41},"Community",[42,45,48],{"label":43,"href":44,"external":32},"Discord","url:social.discord",{"label":46,"href":47,"external":32},"X \u002F Twitter","url:social.x",{"label":49,"href":50,"external":32},"LinkedIn","url:social.linkedin",{"title":52,"links":53},"Company",[54,57,60],{"label":55,"href":56},"About","\u002Fabout",{"label":58,"href":59},"Updates","\u002Fupdates",{"label":61,"href":62},"Contact","\u002Fcontact",[64,67,70],{"label":65,"href":66},"Privacy Policy","\u002Flegal\u002Fprivacy",{"label":68,"href":69},"Refund Policy","\u002Flegal\u002Frefund",{"label":71,"href":72},"Terms of Service","\u002Flegal\u002Fterms",{"links":74,"signIn":75,"contact":78,"cta":80},[],{"label":76,"href":77},"Sign in","url:portal.home",{"label":79,"href":62},"Get in touch",{"label":81,"href":82},"Download","url:routes.downloads",{},"data\u002Fshared\u002Fnavigation","VdirGIa8cUm6xLprbBeTKcw914JfyJjWfF-9hSVOX5Y",{"id":87,"extension":5,"links":88,"meta":660,"stem":661,"__hash__":662},"urlSettings\u002Fdata\u002Fshared\u002Furls.yml",[89,93,97,101,105,109,113,117,121,125,129,133,137,141,145,149,153,157,161,165,169,173,177,181,185,189,192,196,200,204,208,212,216,220,224,228,232,236,240,244,248,252,256,260,264,268,272,276,280,284,288,292,295,299,303,306,310,314,318,322,326,330,334,338,342,346,350,354,358,362,366,370,374,378,382,386,390,394,398,402,406,410,414,418,422,426,430,434,438,442,446,450,453,457,461,465,469,473,477,480,483,486,489,493,497,500,504,508,512,516,520,524,528,532,536,540,544,548,551,555,559,563,567,571,574,577,580,584,587,591,595,599,603,606,610,614,617,620,623,627,631,635,638,641,644,648,652,656],{"key":90,"label":91,"href":92},"downloads.desktop","Desktop download page","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fdesktop\u002Fdownload",{"key":94,"label":95,"href":96},"downloads.macOS.dmgArm64","macOS DMG Apple Silicon","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fpieces_for_x\u002Fdmg-arm64\u002Fdownload",{"key":98,"label":99,"href":100},"downloads.macOS.dmgIntel","macOS DMG Intel","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fpieces_for_x\u002Fdmg\u002Fdownload",{"key":102,"label":103,"href":104},"downloads.macOS.pkg","macOS PKG","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fmacos_packaging\u002Fpkg\u002Fdownload",{"key":106,"label":107,"href":108},"downloads.macOS.universal","Desktop macOS Universal","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fpieces_for_x\u002Fmacos-universal\u002Fdownload",{"key":110,"label":111,"href":112},"downloads.macOS.pkgArm64","Desktop macOS PKG Apple Silicon","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fmacos_packaging\u002Fpkg-pfd-arm64\u002Fdownload",{"key":114,"label":115,"href":116},"downloads.macOS.pkgIntel","Desktop macOS PKG Intel","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fmacos_packaging\u002Fpkg-pfd\u002Fdownload",{"key":118,"label":119,"href":120},"downloads.windows.appinstaller","Windows App Installer","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fappinstaller\u002Fpieces_for_x.appinstaller",{"key":122,"label":123,"href":124},"downloads.windows.exe","Windows EXE","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fpieces_for_x\u002Fwindows-exe\u002Fdownload",{"key":126,"label":127,"href":128},"downloads.windows.msix","Windows MSIX","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fpieces_for_x\u002Fwindows-msix\u002Fdownload",{"key":130,"label":131,"href":132},"downloads.windows.suiteManager","Windows Suite Manager","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fpieces_suite_windows\u002Fappinstaller\u002Fdownload",{"key":134,"label":135,"href":136},"downloads.linux.flatpakRepo","Linux Flatpak repository","https:\u002F\u002Fbuilds.pieces.app\u002Fpieces-flatpak-repo\u002Fpieces-flatpak.flatpakrepo",{"key":138,"label":139,"href":140},"downloads.linux.snapDesktop","Linux Snap Desktop","https:\u002F\u002Fsnapcraft.io\u002Fpieces-for-developers",{"key":142,"label":143,"href":144},"downloads.linux.snapPiecesOS","Linux Snap PiecesOS","https:\u002F\u002Fsnapcraft.io\u002Fpieces-os",{"key":146,"label":147,"href":148},"downloads.linux.snap","Desktop Linux Snap package","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fpieces_for_x\u002Fsnap\u002Fdownload",{"key":150,"label":151,"href":152},"downloads.piecesOS.macOS.dmgArm64","PiecesOS macOS DMG Apple Silicon","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fos_server\u002Fdmg-arm64\u002Fdownload",{"key":154,"label":155,"href":156},"downloads.piecesOS.macOS.dmgIntel","PiecesOS macOS DMG Intel","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fos_server\u002Fdmg\u002Fdownload",{"key":158,"label":159,"href":160},"downloads.piecesOS.macOS.universal","PiecesOS macOS Universal","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fos_server\u002Fmacos-universal\u002Fdownload",{"key":162,"label":163,"href":164},"downloads.piecesOS.macOS.pkgArm64","PiecesOS macOS PKG Apple Silicon","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fmacos_packaging\u002Fpkg-pos-launch-only-arm64\u002Fdownload",{"key":166,"label":167,"href":168},"downloads.piecesOS.macOS.pkgIntel","PiecesOS macOS PKG Intel","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fmacos_packaging\u002Fpkg-pos-launch-only\u002Fdownload",{"key":170,"label":171,"href":172},"downloads.piecesOS.windows.appinstaller","PiecesOS Windows App Installer","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fappinstaller\u002Fos_server.appinstaller",{"key":174,"label":175,"href":176},"downloads.piecesOS.windows.exe","PiecesOS Windows EXE","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fos_server\u002Fwindows-exe\u002Fdownload",{"key":178,"label":179,"href":180},"downloads.piecesOS.windows.msix","PiecesOS Windows MSIX","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fos_server\u002Fwindows-msix\u002Fdownload",{"key":182,"label":183,"href":184},"downloads.piecesOS.linux.snap","PiecesOS Linux Snap package","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fos_server\u002Fsnap\u002Fdownload",{"key":186,"label":187,"href":188},"downloads.combined.macOS.appleSilicon","Combined macOS installer Apple Silicon","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fmacos_packaging\u002Fpkg-arm64\u002Fdownload",{"key":190,"label":191,"href":104},"downloads.combined.macOS.intel","Combined macOS installer Intel",{"key":193,"label":194,"href":195},"downloads.guides.macOS","macOS installation guide","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmeet-pieces\u002Fmacos-installation-guide",{"key":197,"label":198,"href":199},"downloads.guides.windows","Windows installation guide","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmeet-pieces\u002Fwindows-installation-guide",{"key":201,"label":202,"href":203},"downloads.guides.linux","Linux installation guide","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmeet-pieces\u002Flinux-installation-guide",{"key":205,"label":206,"href":207},"downloads.guides.piecesOS","PiecesOS manual installation","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fcore-dependencies\u002Fpieces-os\u002Fmanual-installation",{"key":209,"label":210,"href":211},"extensions.chrome","Chrome extension","https:\u002F\u002Fchrome.google.com\u002Fwebstore\u002Fdetail\u002Fpieces-save-code-snippets\u002Figbgibhbfonhmjlechmeefimncpekepm",{"key":213,"label":214,"href":215},"extensions.firefox","Firefox add-on","https:\u002F\u002Faddons.mozilla.org\u002Fen-US\u002Ffirefox\u002Faddon\u002Fpieces-save-code-from-the-web\u002F",{"key":217,"label":218,"href":219},"extensions.edge","Edge add-on","https:\u002F\u002Fmicrosoftedge.microsoft.com\u002Faddons\u002Fdetail\u002Fpieces-save-code-snippet\u002Fhglfimcdgonaeeobjckfdabcldfidmim",{"key":221,"label":222,"href":223},"extensions.vscode","VS Code extension","https:\u002F\u002Fmarketplace.visualstudio.com\u002Fitems?itemName=MeshIntelligentTechnologiesInc.pieces-vscode",{"key":225,"label":226,"href":227},"extensions.visualStudio","Visual Studio extension","https:\u002F\u002Fmarketplace.visualstudio.com\u002Fitems?itemName=MeshIntelligentTechnologiesInc.PiecesVisualStudio",{"key":229,"label":230,"href":231},"extensions.jetbrains","JetBrains plugin","https:\u002F\u002Fplugins.jetbrains.com\u002Fplugin\u002F17328-pieces--save-search-share--reuse-code-snippets",{"key":233,"label":234,"href":235},"extensions.obsidian","Obsidian plugin","https:\u002F\u002Fobsidian.md\u002Fplugins?id=pieces-for-developers",{"key":237,"label":238,"href":239},"extensions.sublime","Sublime package","https:\u002F\u002Fpackagecontrol.io\u002Fpackages\u002FPieces",{"key":241,"label":242,"href":243},"extensions.neovim","Neovim plugin","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fplugin_neo_vim",{"key":245,"label":246,"href":247},"extensions.jupyterlab","JupyterLab plugin","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fjupyterlab-pieces",{"key":249,"label":250,"href":251},"extensions.cli","Pieces CLI","https:\u002F\u002Fpypi.org\u002Fproject\u002Fpieces-cli\u002F",{"key":253,"label":254,"href":255},"docs.home","Documentation home","https:\u002F\u002Fdocs.pieces.app",{"key":257,"label":258,"href":259},"docs.getStarted","Get started docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmeet-pieces",{"key":261,"label":262,"href":263},"docs.api","API docs","https:\u002F\u002Fdocs.pieces.app\u002Fapi",{"key":265,"label":266,"href":267},"docs.desktop.overview","Desktop overview","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fdesktop",{"key":269,"label":270,"href":271},"docs.desktop.onboarding","Desktop onboarding","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fdesktop\u002Fonboarding",{"key":273,"label":274,"href":275},"docs.desktop.timeline","Desktop timeline docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fdesktop\u002Ftimeline",{"key":277,"label":278,"href":279},"docs.desktop.summaries","Desktop summaries docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fdesktop\u002Fsingle-click-summaries",{"key":281,"label":282,"href":283},"docs.desktop.search","Desktop conversational search docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fdesktop\u002Fconversational-search",{"key":285,"label":286,"href":287},"docs.desktop.drive","Desktop drive docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fdesktop\u002Fdrive",{"key":289,"label":290,"href":291},"docs.desktop.account","Desktop account settings docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fdesktop\u002Fconfiguration\u002Faccount",{"key":293,"label":294,"href":92},"docs.desktop.download","Desktop download docs",{"key":296,"label":297,"href":298},"docs.piecesOS.overview","PiecesOS overview docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fcore-dependencies",{"key":300,"label":301,"href":302},"docs.piecesOS.details","PiecesOS details docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fcore-dependencies\u002Fpieces-os",{"key":304,"label":305,"href":207},"docs.piecesOS.install","PiecesOS install docs",{"key":307,"label":308,"href":309},"docs.piecesOS.quickMenu","PiecesOS quick menu docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fcore-dependencies\u002Fpieces-os\u002Fquick-menu",{"key":311,"label":312,"href":313},"docs.piecesOS.storage","On-device storage docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fcore-dependencies\u002Fon-device-storage",{"key":315,"label":316,"href":317},"docs.piecesOS.troubleshooting","PiecesOS troubleshooting docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fcore-dependencies\u002Fpieces-os\u002Ftroubleshooting",{"key":319,"label":320,"href":321},"docs.mcp.overview","MCP overview docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp",{"key":323,"label":324,"href":325},"docs.mcp.cursor","MCP Cursor docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fcursor",{"key":327,"label":328,"href":329},"docs.mcp.vscode","MCP VS Code docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fvs-code",{"key":331,"label":332,"href":333},"docs.mcp.claudeDesktop","MCP Claude Desktop docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fclaude-desktop",{"key":335,"label":336,"href":337},"docs.mcp.claudeCode","MCP Claude Code docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fclaude-code",{"key":339,"label":340,"href":341},"docs.mcp.claudeCowork","MCP Claude Cowork docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fclaude-cowork",{"key":343,"label":344,"href":345},"docs.mcp.githubCopilot","MCP GitHub Copilot docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fgithub-copilot",{"key":347,"label":348,"href":349},"docs.mcp.goose","MCP Goose docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fgoose",{"key":351,"label":352,"href":353},"docs.mcp.windsurf","MCP Windsurf docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fwindsurf",{"key":355,"label":356,"href":357},"docs.mcp.zed","MCP Zed docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fzed",{"key":359,"label":360,"href":361},"docs.mcp.jetbrains","MCP JetBrains docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fjetbrains-ides",{"key":363,"label":364,"href":365},"docs.mcp.continueDev","MCP Continue docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fcontinue-dev",{"key":367,"label":368,"href":369},"docs.mcp.cline","MCP Cline docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fcline",{"key":371,"label":372,"href":373},"docs.mcp.raycast","MCP Raycast docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fraycast",{"key":375,"label":376,"href":377},"docs.mcp.rovoDevCli","MCP Rovo Dev CLI docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Frovo-dev-cli",{"key":379,"label":380,"href":381},"docs.mcp.openaiCodexCli","MCP OpenAI Codex CLI docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fopenai-codex-cli",{"key":383,"label":384,"href":385},"docs.mcp.googleGeminiCli","MCP Google Gemini CLI docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fgoogle-gemini-cli",{"key":387,"label":388,"href":389},"docs.mcp.amazonQ","MCP Amazon Q docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Famazon-q-developer",{"key":391,"label":392,"href":393},"docs.mcp.chatgptDev","MCP ChatGPT Developer Mode docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fchatgpt-developer-mode",{"key":395,"label":396,"href":397},"docs.mcp.openclaw","MCP OpenClaw docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fopenclaw",{"key":399,"label":400,"href":401},"docs.mcp.mcpRemote","MCP Remote docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fmcp-remote",{"key":403,"label":404,"href":405},"docs.mcp.ngrok","MCP ngrok docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fngrok-setup",{"key":407,"label":408,"href":409},"docs.troubleshooting.macOS","macOS troubleshooting docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmeet-pieces\u002Ftroubleshooting\u002Fmacos",{"key":411,"label":412,"href":413},"docs.troubleshooting.windows","Windows troubleshooting docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmeet-pieces\u002Ftroubleshooting\u002Fwindows",{"key":415,"label":416,"href":417},"docs.troubleshooting.linux","Linux troubleshooting docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmeet-pieces\u002Ftroubleshooting\u002Flinux",{"key":419,"label":420,"href":421},"docs.privacy","Privacy and security docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fprivacy-security-your-data",{"key":423,"label":424,"href":425},"docs.support","Support docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fsupport",{"key":427,"label":428,"href":429},"portal.home","Pieces portal","https:\u002F\u002Fportal.pieces.app",{"key":431,"label":432,"href":433},"site.home","Website home","https:\u002F\u002Fpieces.app",{"key":435,"label":436,"href":437},"site.about","About page","https:\u002F\u002Fpieces.app\u002Fabout",{"key":439,"label":440,"href":441},"site.features","Features page","https:\u002F\u002Fpieces.app\u002Ffeatures",{"key":443,"label":444,"href":445},"site.plugins","Plugins page","https:\u002F\u002Fpieces.app\u002Fplugins",{"key":447,"label":448,"href":449},"site.contact","Contact page","https:\u002F\u002Fpieces.app\u002Fcontact",{"key":451,"label":58,"href":452},"site.updates","https:\u002F\u002Fpieces.app\u002Fupdates",{"key":454,"label":455,"href":456},"site.news","News","https:\u002F\u002Fpieces.app\u002Fnews",{"key":458,"label":459,"href":460},"site.events","Community events","https:\u002F\u002Fpieces.app\u002Fcommunity\u002Fevents",{"key":462,"label":463,"href":464},"site.userStories","User stories","https:\u002F\u002Fpieces.app\u002Fuser-stories",{"key":466,"label":467,"href":468},"site.academy","Academy","https:\u002F\u002Fpieces.app\u002Flearn\u002Facademy",{"key":470,"label":471,"href":472},"site.support","Website support","https:\u002F\u002Fpieces.app\u002Fsupport",{"key":474,"label":475,"href":476},"site.standup","Standup","https:\u002F\u002Fpieces.app\u002Fstandup",{"key":478,"label":34,"href":479},"site.blog","https:\u002F\u002Fcode.pieces.app\u002Fblog",{"key":481,"label":43,"href":482},"social.discord","https:\u002F\u002Fdiscord.gg\u002Fgetpieces",{"key":484,"label":46,"href":485},"social.x","https:\u002F\u002Fx.com\u002Fgetpieces",{"key":487,"label":488,"href":485},"social.twitter","Twitter",{"key":490,"label":491,"href":492},"social.instagram","Instagram","https:\u002F\u002Fwww.instagram.com\u002Fgetpieces\u002F",{"key":494,"label":495,"href":496},"social.tiktok","TikTok","https:\u002F\u002Fwww.tiktok.com\u002F@getpieces",{"key":498,"label":49,"href":499},"social.linkedin","https:\u002F\u002Fwww.linkedin.com\u002Fcompany\u002Fgetpieces\u002F",{"key":501,"label":502,"href":503},"social.youtube","YouTube","https:\u002F\u002Fyoutube.com\u002F@getpieces",{"key":505,"label":506,"href":507},"github.org","GitHub organization","https:\u002F\u002Fgithub.com\u002Fpieces-app",{"key":509,"label":510,"href":511},"github.support","GitHub support","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fsupport",{"key":513,"label":514,"href":515},"github.issues","GitHub issues","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fsupport\u002Fissues",{"key":517,"label":518,"href":519},"github.discussions","GitHub discussions","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fsupport\u002Fdiscussions",{"key":521,"label":522,"href":523},"github.documentation","GitHub documentation","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fdocumentation",{"key":525,"label":526,"href":527},"github.opensource","GitHub open source","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fopensource",{"key":529,"label":530,"href":531},"github.sdks.python","Python SDK","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fpieces-os-client-sdk-for-python",{"key":533,"label":534,"href":535},"github.sdks.typescript","TypeScript SDK","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fpieces-os-client-sdk-for-typescript",{"key":537,"label":538,"href":539},"github.sdks.dart","Dart SDK","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fpieces-os-client-sdk-for-dart",{"key":541,"label":542,"href":543},"github.sdks.kotlin","Kotlin SDK","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fpieces-os-client-sdk-for-kotlin",{"key":545,"label":546,"href":547},"github.plugins.obsidian","Obsidian plugin repository","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fobsidian-pieces",{"key":549,"label":550,"href":247},"github.plugins.jupyterlab","JupyterLab plugin repository",{"key":552,"label":553,"href":554},"github.plugins.sublime","Sublime plugin repository","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fplugin_sublime",{"key":556,"label":557,"href":558},"github.plugins.neovim","Neovim plugin repository","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fplugin_neovim",{"key":560,"label":561,"href":562},"github.cliAgent","CLI agent repository","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fcli-agent",{"key":564,"label":565,"href":566},"github.mcpDart","MCP Dart repository","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fmcp_dart",{"key":568,"label":569,"href":570},"github.awesomePieces","Awesome Pieces repository","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fawesome-pieces",{"key":572,"label":573,"href":66},"legal.privacyPolicy","Privacy policy",{"key":575,"label":576,"href":69},"legal.refundPolicy","Refund policy",{"key":578,"label":579,"href":72},"legal.terms","Terms",{"key":581,"label":582,"href":583},"legal.security","Legal security","https:\u002F\u002Fpieces.app\u002Flegal\u002Fsecurity",{"key":585,"label":586,"href":503},"videos.youtubeChannel","YouTube channel",{"key":588,"label":589,"href":590},"videos.gettingStartedDesktop","Getting started desktop video","https:\u002F\u002Fyoutu.be\u002FdUr1lRM_TYk",{"key":592,"label":593,"href":594},"videos.snippetDiscoveryxR","Snippet discovery video","https:\u002F\u002Fyoutu.be\u002FG6vb1USw-30",{"key":596,"label":597,"href":598},"sales.bookACall","Book a sales call","https:\u002F\u002Fcalendar.app.google\u002FWVUDtUfNy5Vst3sH7",{"key":600,"label":601,"href":602},"sales.enterprise","Enterprise form","https:\u002F\u002Fgetpieces.typeform.com\u002Fto\u002FaVQFTvpE",{"key":604,"label":605,"href":519},"sales.feedback","Feedback discussions",{"key":607,"label":608,"href":609},"sales.earlyAccess","Early access form","https:\u002F\u002Fgetpieces.typeform.com\u002Fearlyaccess",{"key":611,"label":612,"href":613},"sales.supportEmail","Support email","mailto:support@pieces.app",{"key":615,"label":616,"href":19},"routes.home","Home route",{"key":618,"label":619,"href":56},"routes.about","About route",{"key":621,"label":622,"href":12},"routes.downloads","Downloads route",{"key":624,"label":625,"href":626},"routes.thanks","Post-install thanks route","\u002Finstall\u002Fthanks",{"key":628,"label":629,"href":630},"routes.pricing","Pricing route","\u002Fpricing",{"key":632,"label":633,"href":634},"cta.freeTrial","Start free trial CTA (Pieces Pro) — used by \u002Fcampaigns\u002F* landing pages","https:\u002F\u002Fcampaigns.pieces.app\u002F",{"key":636,"label":637,"href":22},"routes.enterprise","Enterprise route",{"key":639,"label":640,"href":62},"routes.contact","Contact route",{"key":642,"label":643,"href":59},"routes.updates","Updates route",{"key":645,"label":646,"href":647},"routes.migrationError","Migration error route","\u002Fmigration\u002Ferror",{"key":649,"label":650,"href":651},"routes.authenticated","Post-login authenticated route","\u002Fauth\u002Fsigned-in",{"key":653,"label":654,"href":655},"routes.signed-out","Signed out route","\u002Fauth\u002Fsigned-out",{"key":657,"label":658,"href":659},"routes.authentication-error","Authentication error route","\u002Fauth\u002Ferror",{},"data\u002Fshared\u002Furls","NLkVE1lIUws518K-1QsSB6T-GvlXYIzcRL1HDhqarGQ",{"id":664,"title":665,"author":666,"authorPhoto":667,"authorPhotoAlt":668,"authorSlug":669,"body":670,"buttonText":1069,"buttonUrl":1069,"category":1070,"date":1071,"description":1072,"draft":1073,"editorsPick":1073,"extension":1074,"featured":1073,"image":1075,"imageAlt":1076,"meta":1077,"navigation":32,"ogImage":1069,"ogImageAlt":1069,"path":1078,"seo":1079,"stem":1080,"tags":1069,"__hash__":1081},"blog\u002Fblog\u002Freact-form-validation-informed.md","React Form Validation with Informed","Clarence Bakosi","https:\u002F\u002Fstorage.googleapis.com\u002Fpieces-marketing-website\u002Fimages\u002Fblog\u002Freact-form-validation-informed\u002Fauthor.png","Clarence Bakosi.","clarence-bakosi",{"type":671,"value":672,"toc":1056},"minimark",[673,677,682,692,697,700,711,714,720,727,733,736,743,749,752,759,763,766,771,777,783,794,800,804,813,819,852,858,862,867,873,883,889,893,898,904,913,919,923,927,933,939,945,949,968,974,980,984,991,997,1003,1007,1018,1024,1032,1038,1042],[674,675,676],"p",{},"Form validation is an effective way to control the type of values that are provided in the proper format, preventing security vulnerabilities, malicious users, and entering incorrect data. It guarantees the data submitted matches the requirement. There are many validation frameworks\u002Flibraries that are used to handle React form validation in web applications; Informed is one such tool.",[678,679,681],"h2",{"id":680},"what-is-informed","What is Informed?",[674,683,684,691],{},[685,686,690],"a",{"href":687,"rel":688},"https:\u002F\u002Fwww.npmjs.com\u002Fpackage\u002Finformed",[689],"nofollow","Informed"," is a React form validation tool used to create robust forms. It’s a simple framework that enables you to add custom inputs, dynamic forms, and multi-step forms to your application while making it simple to specify input error messages. It resolves the hassle of handling form state.",[693,694,696],"h3",{"id":695},"getting-started-with-informed","Getting Started With Informed",[674,698,699],{},"This section will walk you through integrating the Informed React validation library into your application, along with validating fields and creating custom inputs. In addition, we'll create a React application and install the Informed library by performing either of the following commands:",[701,702,707],"pre",{"className":703,"code":705,"language":706},[704],"language-text","yarn add informed\n","text",[708,709,705],"code",{"__ignoreMap":710},"",[674,712,713],{},"or",[701,715,718],{"className":716,"code":717,"language":706},[704],"npm install informed\n",[708,719,717],{"__ignoreMap":710},[674,721,722,723,726],{},"After installing the library, we’ll modify our ",[708,724,725],{},"App.css"," file by pasting the code block below:",[701,728,731],{"className":729,"code":730,"language":706},[704],"* {\noverflow-x: hidden;\n}\n.App {\n  display: flex;\n  flex-direction: column;\n  justify-content: center;\n  align-items: center;\n  background-color: #fff;\n  color: #000;\n  min-height: 100vh;\n  width: 100vw;\n  padding: 20px;\n}\nform {\n  display: flex;\n  flex-direction: row;\n  justify-content: space-between;\n  align-items: flex-start;\n  width: 700px;\n  padding: 15px;\n  box-shadow: 10px 10px 15px lightblue;\n  border: 1px solid #eee;\n  border-radius: 2px;\n}\ndiv {\n  display: flex;\n  flex-direction: column;\n  width: 100%;\n  padding: 5px;\n}\ninput {\n  width: -webkit-fill-available;\n  padding: 5px 10px;\n  margin: 5px 0;\n}\nbutton {\n  border: none;\n  margin-top: 10px;\n  padding: 10px 25px;\n  border-radius: 5px;\n  color: #fff;\n  background-color: #000;\n  cursor: pointer;\n}\nspan {\n  color: #ff0000;\n}\n",[708,732,730],{"__ignoreMap":710},[678,734,665],{"id":735},"react-form-validation-with-informed",[674,737,738,739,742],{},"In this section, we’ll go over how to include Informed in your application. By default, the Informed library features native DOM input elements that are controlled by the React form library. This makes it easy to retrieve and manipulate form values; it handles everything related to the form state. Using the code block below, we’ll alter the ",[708,740,741],{},"App.js"," component:",[701,744,747],{"className":745,"code":746,"language":706},[704],"import { Form, Input, Debug } from 'informed';\nimport '.\u002FApp.css';\n\nconst App = () => (\n \u003Cdiv className=\"App\">\n     \u003CForm>\n      \u003Cdiv>\n       \u003CInput className=\"input\" name=\"name\" label=\"Name\" placeholder=\"Elon\" \u002F>\n       \u003CInput\n        className=\"input\"\n        name=\"age\"\n        type=\"number\"\n        label=\"Age\"\n       \u002F>\n       \u003CInput\n        className=\"input\"\n        name=\"phone\"\n        label=\"Phone\"\n        formatter=\"+234 (###)-###-####\"\n       \u002F>\n      \u003Cbutton type=\"submit\">Submit\u003C\u002Fbutton>\n     \u003C\u002Fdiv>\n     \u003CDebug\u002F>\n    \u003C\u002FForm>\n  \u003C\u002Fdiv>\n);\n\nexport default App;\n",[708,748,746],{"__ignoreMap":710},[674,750,751],{},"The code block above demonstrates how components imported from the Informed library are simply implemented. It’s critical to note the Debug component; this component displays the whole state of your form in real time, allowing for easier debugging. Also, the formatter prop shows you how to format input values. This can be added to text inputs as well.",[674,753,754],{},[755,756],"img",{"alt":757,"src":758},"An example of React form validation.","https:\u002F\u002Fstorage.googleapis.com\u002Fpieces-marketing-website\u002Fimages\u002Fblog\u002Freact-form-validation-informed\u002Fimg-001.png",[693,760,762],{"id":761},"validation-hooks","Validation Hooks",[674,764,765],{},"The Informed library has a variety of hooks that help with various parts of managing simple to complex React forms in your application. We'll be looking at it in this section:",[767,768,770],"h4",{"id":769},"useformstate","useFormState",[674,772,773,774,776],{},"The ",[708,775,770],{}," hook from the Informed library gives you access to the form state properties:",[701,778,781],{"className":779,"code":780,"language":706},[704],"import { Form, Input, useFormState } from 'informed';\n\nconst ComponentUsingFormState = () => {\n const formState = useFormState();\n return (\n  \u003Cpre>\n   \u003Ccode>{JSON.stringify(formState.values, null, 2)}\u003C\u002Fcode>\n  \u003C\u002Fpre>\n );\n};\n\nconst App = () => (\n \u003Cdiv className=\"App\">\n  \u003CForm>\n  \u003Cdiv>\n   \u003CInput name=\"name\" label=\"Name:\" \u002F>\n   \u003CInput name=\"occupation\" label=\"Occupation:\" \u002F>\n   \u003Cbutton type=\"submit\">Submit\u003C\u002Fbutton>\n  \u003C\u002Fdiv>\n  \u003Cdiv>\n   \u003Ch5>Component using formState:\u003C\u002Fh5>\n   \u003CComponentUsingFormState \u002F>\n  \u003C\u002Fdiv>\n  \u003C\u002FForm>\n \u003C\u002Fdiv>\n);\n",[708,782,780],{"__ignoreMap":710},[674,784,785,786,789,790,793],{},"In the code block above, in ",[708,787,788],{},"ComponentUsingFormState",", you can access the form values by using the dot notation ",[708,791,792],{},"formState.values",":",[674,795,796],{},[755,797],{"alt":798,"src":799},"formState output with Informed.","https:\u002F\u002Fstorage.googleapis.com\u002Fpieces-marketing-website\u002Fimages\u002Fblog\u002Freact-form-validation-informed\u002Fimg-002.png",[767,801,803],{"id":802},"useformapi","useFormApi",[674,805,773,806,808,809,812],{},[708,807,803],{}," hook from the Informed library allows you to gain access to the form API functions. You can alter the value of an input using the functions that ",[708,810,811],{},"formApi"," provides for React form validation:",[701,814,817],{"className":815,"code":816,"language":706},[704],"...\n\nimport { Form, Input, useFormApi } from \"informed\";\n\nconst RandomSetterButton = () => {\n const formApi = useFormApi();\n return (\n  \u003Cbutton\n   type=\"button\"\n   onClick={() =>\n    formApi.setValue(\n     \"name\",\n     Math.floor(Math.random() * Math.floor(Number.MAX_SAFE_INTEGER))\n    )\n   }\n  >\n   Random\n   \u003C\u002Fbutton>\n );\n};\n\nconst SetValuesButton = () => {\n const formApi = useFormApi();\n return (\n  \u003Cbutton\n   type=\"button\"\n   onClick={() => formApi.setValues({ name: 'Asta', age: 26, color: \"Green\" })}\n  >\n   All\n  \u003C\u002Fbutton>\n );\n};\n\nconst SetTheseValuesButton = () => {\n const formApi = useFormApi();\n  return (\n   \u003Cbutton\n    type=\"button\"\n    onClick={() => formApi.setTheseValues({ age: 27, color: \"Yellow\" })}\n   >\n    Age & Color\n   \u003C\u002Fbutton>\n  );\n};\n\nconst App = () => (\n \u003CForm onSubmit={({ values }) => window.alert(JSON.stringify(values, null, 2))}>\n  \u003Cdiv>\n   \u003CInput name=\"name\" label=\"First Name:\" \u002F>\n   \u003CInput name=\"age\" label=\"First Name:\" type=\"number\"  \u002F>\n   \u003CInput name=\"color\" label=\"Favorite Color:\" \u002F>\n   \u003CRandomSetterButton \u002F>\n   \u003CSetValuesButton \u002F>\n   \u003CSetTheseValuesButton \u002F>\n   \u003Cbutton type=\"submit\">Submit\u003C\u002Fbutton>\n  \u003C\u002Fdiv>\n \u003C\u002FForm>\n);\n\n...\n",[708,818,816],{"__ignoreMap":710},[674,820,821,822,825,826,829,830,833,834,837,838,825,841,844,845,847,848,851],{},"As shown in the code block above, the ",[708,823,824],{},"RandomSetterButton"," component uses ",[708,827,828],{},"setValue"," to target a single input. In this case, the name input is targeted, and the value is set to a random number. The ",[708,831,832],{},"SetTheseValuesButton"," component uses the ",[708,835,836],{},"setTheseValues"," function to change the values of name, age, and color inputs. Also, the ",[708,839,840],{},"SetValuesButton",[708,842,843],{},"setValues"," to set the input values of both age and color to different values. One of the important ",[708,846,803],{}," functions is the ",[708,849,850],{},"onSubmit"," function. This gives you access to the form values, which can be used as payload to an endpoint.",[674,853,854],{},[755,855],{"alt":856,"src":857},"React form validation example.","https:\u002F\u002Fstorage.googleapis.com\u002Fpieces-marketing-website\u002Fimages\u002Fblog\u002Freact-form-validation-informed\u002Fimg-003.png",[767,859,861],{"id":860},"usefieldapi","useFieldApi",[674,863,773,864,866],{},[708,865,861],{}," hook gives you access to the field API functions using a dot notation:",[701,868,871],{"className":869,"code":870,"language":706},[704],"...\n\nimport { Form, Input, useFieldApi } from \"informed\";\n\nconst ComponentUsingFieldApi = () => {\n const fieldApi = useFieldApi(\"name\");\n return (\n  \u003Cbutton\n   type=\"button\"\n   onClick={() =>\n    fieldApi.setValue(\n     ' Math.floor(Math.random() * Math.floor(Number.MAX_SAFE_INTEGER))'\n    )\n   }\n  >\n   Random\n  \u003C\u002Fbutton>\n );\n};\n\nconst App = () => (\n \u003CForm>\n  \u003Cdiv>\n   \u003CInput name=\"name\" label=\"Name:\" initialValue=\"Joe\" \u002F>\n   \u003Cbutton type=\"submit\">Submit\u003C\u002Fbutton>\n   \u003Ch5>Component using fieldApi:\u003C\u002Fh5>\n  \u003CComponentUsingFieldApi\u002F>\n  \u003C\u002Fdiv>\n \u003C\u002FForm>\n);\n\n...\n",[708,872,870],{"__ignoreMap":710},[674,874,773,875,878,879,882],{},[708,876,877],{},"name"," field having the ",[708,880,881],{},"initialValue"," Meliodas, changes to a random number when the random button is clicked:",[674,884,885],{},[755,886],{"alt":887,"src":888},"useFieldApi output with Informed.","https:\u002F\u002Fstorage.googleapis.com\u002Fpieces-marketing-website\u002Fimages\u002Fblog\u002Freact-form-validation-informed\u002Fimg-004.png",[767,890,892],{"id":891},"usefieldstate","useFieldState",[674,894,773,895,897],{},[708,896,892],{}," hook gives you access to the field state attributes:",[701,899,902],{"className":900,"code":901,"language":706},[704],"...\n\nimport { Form, Input, useFieldState } from 'informed';\n\nconst ComponentUsingFieldState = ({ name }) => {\n const fieldState = useFieldState(name);\n return (\n  \u003C>\n   \u003Ch5>Component using fieldState: {name}\u003C\u002Fh5>\n   Render: {Math.random()}\n   \u003Cpre>\n    \u003Ccode>{JSON.stringify(fieldState, null, 2)}\u003C\u002Fcode>\n   \u003C\u002Fpre>\n  \u003C\u002F>\n );\n};\n\nconst App = () => (\n \u003CForm>\n  \u003Cdiv>\n   \u003CInput name=\"name\" label=\"Name:\" \u002F>\n   \u003CInput field=\"age\" label=\"Age:\" type=\"number\" \u002F>\n   \u003Cbutton type=\"submit\">Submit\u003C\u002Fbutton>\n  \u003C\u002Fdiv>\n  \u003Cdiv>\n   \u003CComponentUsingFieldState name=\"name\" \u002F>\n   \u003CComponentUsingFieldState name=\"age\" \u002F>\n  \u003C\u002Fdiv>\n \u003C\u002FForm>\n);\n\n...\n",[708,903,901],{"__ignoreMap":710},[674,905,906,907,909,910,912],{},"From the code block above, the ",[708,908,877],{}," field is passed into the ",[708,911,892],{}," hook as an argument, and can be used to keep track of every name attribute in the form state:",[674,914,915],{},[755,916],{"alt":917,"src":918},"useField State example with Informed.","https:\u002F\u002Fstorage.googleapis.com\u002Fpieces-marketing-website\u002Fimages\u002Fblog\u002Freact-form-validation-informed\u002Fimg-005.png",[693,920,922],{"id":921},"form-validation-methods","Form Validation Methods",[767,924,926],{"id":925},"simple-validation","Simple Validation",[674,928,929,930,793],{},"Informed forms provide the validate prop to handle field-level validation. You can pass in rules from a function to validate an input field, or mark it as ",[708,931,932],{},"required",[701,934,937],{"className":935,"code":936,"language":706},[704],"...\n\nimport { Form, Text } from 'informed';\n\nconst validate = (value) => {\n if (!value || value.length \u003C 5)\n  return (\n   \u003Cspan>Field must be at least five characters\u003C\u002Fspan>\n  )\n};\n\nconst App = () => {\n return (\n  \u003CForm\n   onSubmit={({ values }) => window.alert(JSON.stringify(values, null, 2))}>\n   \u003CInput name=\"color\" label=\"Color:\" validate={validate} required \u002F>\n   \u003CInput name=\"food\" label=\"Food:\" validate={validate} \u002F>\n   \u003Cbutton type=\"submit\">Submit\u003C\u002Fbutton>\n  \u003C\u002FForm>\n );\n};\n\n...\n",[708,938,936],{"__ignoreMap":710},[674,940,941],{},[755,942],{"alt":943,"src":944},"An example of simple form validation with Informed.","https:\u002F\u002Fstorage.googleapis.com\u002Fpieces-marketing-website\u002Fimages\u002Fblog\u002Freact-form-validation-informed\u002Fimg-006.png",[767,946,948],{"id":947},"validation-control","Validation Control",[674,950,951,952,955,956,959,960,963,964,967],{},"For more control when validating, passing ",[708,953,954],{},"validateOn"," props to fields makes Informed more flexible in handling React form validation. You can also choose to control when the error message shows using the ",[708,957,958],{},"showErrorIfError",", ",[708,961,962],{},"showErrorIfTouched",", and ",[708,965,966],{},"showErrorIfDirty"," props:",[701,969,972],{"className":970,"code":971,"language":706},[704],"...\n\nconst App = () => (\n  \u003Cdiv className=\"App\">\n  \u003CForm\n   onSubmit={({ values }) => window.alert(JSON.stringify(values, null, 2))}\n  >\n   \u003Cdiv>\n\n    \u003Ch4>validateOn=\"blur\" ( default )\u003C\u002Fh4>\n    \u003CInput\n     name=\"username1\"\n     label=\"Username1\"\n     required\n     validate={validate}\n    \u002F>\n    \u003Ch4>validateOn=\"change\"\u003C\u002Fh4>\n    \u003CInput\n     name=\"username2\"\n     label=\"Username2\"\n     validateOn=\"change\"\n     required\n     validate={validate}\n    \u002F>\n    \u003Ch4>validateOn=\"change\" && showErrorIfDirty\u003C\u002Fh4>\n    \u003CInput\n     name=\"username3\"\n     label=\"Username3\"\n     validateOn=\"change\"\n     showErrorIfDirty\n     required\n     validate={validate}\n    \u002F>\n    \u003Ch4>validateOn=\"change-blur\"\u003C\u002Fh4>\n    \u003CInput\n     name=\"username4\"\n     label=\"Username4\"\n     validateOn=\"change-blur\"\n     required\n     validate={validate}\n    \u002F>\n    \u003Ch4>validateOn=\"change-submit\"\u003C\u002Fh4>\n    \u003CInput\n      name=\"username5\"\n      label=\"Username5\"\n      validateOn=\"change-submit\"\n      required\n      validate={validate}\n    \u002F>\n    \u003Ch4>validateOn=\"blur-submit\"\u003C\u002Fh4>\n    \u003CInput\n     name=\"username6\"\n     label=\"Username6\"\n     validateOn=\"blur-submit\"\n     required\n     validate={validate}\n    \u002F>\n    \u003Ch4>validateOn=\"submit\"\u003C\u002Fh4>\n    \u003CInput\n     name=\"username7\"\n     label=\"Username7\"\n     validateOn=\"submit\"\n     required\n     validate={validate}\n    \u002F>\n    \u003Ch4>validateOnMount\u003C\u002Fh4>\n    \u003CInput\n     name=\"username8\"\n     label=\"Username8\"\n     validateOnMount\n     required\n     validate={validate}\n    \u002F>\n    \u003Ch4>validateOnMount && showErrorIfError\u003C\u002Fh4>\n    \u003CInput\n     name=\"username9\"\n     label=\"Username9\"\n     validateOnMount\n     showErrorIfError\n     required\n     validate={validate}\n    \u002F>\n    \u003Cbutton type=\"submit\">Submit\u003C\u002Fbutton>\n\n   \u003C\u002Fdiv>\n   \u003Cdiv>\n    \u003CDebug values errors invalid validating \u002F>\n    \u003Cbutton type=\"submit\">Submit\u003C\u002Fbutton>\n   \u003C\u002Fdiv>\n  \u003C\u002FForm>\n \u003C\u002Fdiv>\n);\n\n...\n",[708,973,971],{"__ignoreMap":710},[674,975,976],{},[755,977],{"alt":978,"src":979},"An example of validation control in Informed.","https:\u002F\u002Fstorage.googleapis.com\u002Fpieces-marketing-website\u002Fimages\u002Fblog\u002Freact-form-validation-informed\u002Fimg-007.png",[767,981,983],{"id":982},"validation-messages","Validation Messages",[674,985,986,987,990],{},"This method aids you in displaying custom error messages for built-in validations. You can achieve this feat by making use of the ",[708,988,989],{},"errorMessage"," prop:",[701,992,995],{"className":993,"code":994,"language":706},[704],"...\n\nimport {\n Form,\n Input,\n Debug\n} from 'informed';\n\nconst validate = value => {\n if (!value || value.length \u003C 5)\n  return 'Field must be at least five characters';\n};\n\nconst App = () => (\n \u003CForm\n  errorMessage={{ required: 'This field is required for your profile!' }}\n  onSubmit={({ values }) => window.alert(JSON.stringify(values, null, 2))}>\n  \u003CInput\n   name=\"name\"\n   label=\"First name:\"\n   required\n   errorMessage=\"There is a problem with this field!\"\n  \u002F>\n  \u003CInput\n   name=\"last\"\n   label=\"Last name:\"\n   required\n   errorMessage={{ required: 'Last name is required!' }}\n  \u002F>\n  \u003CInput name=\"favoriteColor\" label=\"Favorite color:\" required \u002F>\n  \u003Cbutton type=\"submit\">Submit\u003C\u002Fbutton>\n  \u003CDebug values errors invalid valid \u002F>\n \u003C\u002FForm>\n);\n\n...\n",[708,996,994],{"__ignoreMap":710},[674,998,999],{},[755,1000],{"alt":1001,"src":1002},"Sending validation messages with Informed.","https:\u002F\u002Fstorage.googleapis.com\u002Fpieces-marketing-website\u002Fimages\u002Fblog\u002Freact-form-validation-informed\u002Fimg-008.png",[678,1004,1006],{"id":1005},"basic-form-validation","Basic Form Validation",[674,1008,1009,1010,1013,1014,1017],{},"Informed allows you to create custom validation inputs that can be used across your application. Next, we’ll explore the ",[708,1011,1012],{},"useField"," and ",[708,1015,1016],{},"useForm"," hooks to create a custom form:",[701,1019,1022],{"className":1020,"code":1021,"language":706},[704],"...\n\nimport { useForm, useField, Debug } from 'informed';\n\nconst CustomForm = ({ children, ...rest }) => {\n const { formController, render, userProps } = useForm(rest);\n\n\u002F* --- DON'T FORGET TO CALL THE RENDER METHOD FROM THE HOOK! --- *\u002F\nreturn render(\n \u003Cform\n  {...userProps}\n  onReset={formController.reset}\n  onSubmit={formController.submitForm}\n  onKeyDown={formController.keyDown}>\n  {children}\n \u003C\u002Fform>\n );\n};\n\nconst CustomInput = props => {\n const { render, informed, fieldState, userProps, ref } = useField({\n  type: 'text',\n  ...props\n });\n\nconst { id, label, ...rest } = userProps;\n const { error, showError } = fieldState;\n\n\u002F* --- DON'T FORGET TO CALL THE RENDER METHOD FROM THE HOOK! --- *\u002F\nreturn render(\n \u003C>\n  \u003Clabel htmlFor={id}>{label}\u003C\u002Flabel>\n  \u003Cinput\n   {...rest}\n   {...informed}\n   ref={ref}\n   style={showError ? { border: 'solid 1px red' } : null}\n  \u002F>\n   {showError && \u003Csmall style={{ color: 'red' }}>{error}\u003C\u002Fsmall>}\n  \u003C\u002F>\n );\n};\n\nconst App = () => (\n \u003Cdiv className=\"App\">\n  \u003CCustomForm\n   onSubmit={({ values }) => window.alert(JSON.stringify(values, null, 2))} \n  >\n   \u003Cdiv>\n    \u003CCustomInput\n     field=\"name\"\n     label=\"First name:\"\n     validateOn=\"change\"\n     required\n     minLength={5}\n    \u002F>\n    \u003Cbutton type=\"submit\">Submit\u003C\u002Fbutton>\n   \u003C\u002Fdiv>\n   \u003CDebug values errors \u002F>\n  \u003C\u002FCustomForm>\n \u003C\u002Fdiv>\n);\n\n...\n",[708,1023,1021],{"__ignoreMap":710},[674,1025,1026,1027,1013,1029,1031],{},"Using the ",[708,1028,1012],{},[708,1030,1016],{}," hooks, a custom form and input component was generated in the code block above. When utilizing either hook, you must always call the render method obtained from both hooks:",[674,1033,1034],{},[755,1035],{"alt":1036,"src":1037},"Using custom validations in Informed.","https:\u002F\u002Fstorage.googleapis.com\u002Fpieces-marketing-website\u002Fimages\u002Fblog\u002Freact-form-validation-informed\u002Fimg-009.png",[678,1039,1041],{"id":1040},"conclusion","Conclusion",[674,1043,1044,1045,1013,1050,1055],{},"In this article, we explored the Informed library for handling React form validation in applications. We also covered creating custom inputs and custom validation error messages. To see more of what the library offers, check out their ",[685,1046,1049],{"href":1047,"rel":1048},"https:\u002F\u002Fteslamotors.github.io\u002Finformed\u002F?path=\u002Fstory\u002Fintroduction--getting-started",[689],"docs",[685,1051,1054],{"href":1052,"rel":1053},"https:\u002F\u002Fgithub.com\u002Fteslamotors\u002Finformed",[689],"GitHub repository",".",{"title":710,"searchDepth":1057,"depth":1057,"links":1058},2,[1059,1063,1067,1068],{"id":680,"depth":1057,"text":681,"children":1060},[1061],{"id":695,"depth":1062,"text":696},3,{"id":735,"depth":1057,"text":665,"children":1064},[1065,1066],{"id":761,"depth":1062,"text":762},{"id":921,"depth":1062,"text":922},{"id":1005,"depth":1057,"text":1006},{"id":1040,"depth":1057,"text":1041},null,"Software Development","2022-11-08T00:00:00.000Z","React form validation is an effective way to control the type of values that are provided in a form. Informed can help you manage your forms.",false,"md","https:\u002F\u002Fstorage.googleapis.com\u002Fpieces-marketing-website\u002Fimages\u002Fblog\u002Freact-form-validation-informed\u002Fhero.jpeg","A stack of forms.",{},"\u002Fblog\u002Freact-form-validation-informed",{"title":665,"description":1072},"blog\u002Freact-form-validation-informed","huwWmEuOHJq5zx2I6OGn1gCk2_0TUF7Umu6JQ1FaSA8",{"id":1083,"title":666,"body":1084,"description":710,"draft":1073,"extension":1074,"meta":1088,"navigation":32,"path":1089,"photo":1090,"photoAlt":1069,"seo":1091,"stem":1092,"__hash__":1093},"authors\u002Fauthors\u002Fclarence-bakosi.md",{"type":671,"value":1085,"toc":1086},[],{"title":710,"searchDepth":1057,"depth":1057,"links":1087},[],{},"\u002Fauthors\u002Fclarence-bakosi","https:\u002F\u002Fstorage.googleapis.com\u002Fpieces-marketing-website\u002Fimages\u002Fauthors\u002Fclarence-bakosi.jpg",{"title":666,"description":710},"authors\u002Fclarence-bakosi","qCgIEKGgPAwvBNLGno6tCK7JWX32ibTV3mFxlTrvsNE",{"left":1095,"top":1095,"width":1096,"height":1096,"rotate":1095,"vFlip":1073,"hFlip":1073,"body":1097},0,24,"\u003Cpath fill=\"currentColor\" d=\"m7.825 13l4.9 4.9q.3.3.288.7t-.313.7q-.3.275-.7.288t-.7-.288l-6.6-6.6q-.15-.15-.213-.325T4.426 12t.063-.375t.212-.325l6.6-6.6q.275-.275.688-.275t.712.275q.3.3.3.713t-.3.712L7.825 11H19q.425 0 .713.288T20 12t-.288.713T19 13z\"\u002F>"]