[{"data":1,"prerenderedAt":3231},["ShallowReactive",2],{"\u002Fposts\u002Fforms-without-the-stress":3,"posts-nav":3193},{"id":4,"title":5,"body":6,"date":3180,"description":3181,"draft":3182,"extension":3183,"meta":3184,"navigation":651,"path":3185,"seo":3186,"stem":3187,"subtitle":3188,"tags":3189,"__hash__":3192},"posts\u002Fposts\u002Fforms-without-the-stress.md","Forms without the stress: React hook form does it best!",{"type":7,"value":8,"toc":3167},"minimark",[9,14,18,31,34,37,41,44,48,51,76,80,94,131,134,137,143,177,187,253,260,318,322,329,360,366,620,623,626,997,1001,1007,1042,1048,1056,1059,1084,1090,1093,1110,1129,1140,1146,1493,1496,1578,1581,1584,1606,1613,1622,1673,1676,1696,1699,1726,1729,1777,1780,1787,1797,1917,1926,1929,1932,2294,2297,2300,2303,2487,2495,2498,2502,2508,2511,2546,2549,2564,2582,2865,2871,2897,2901,2904,2938,2941,3092,3097,3119,3130,3134,3137,3140,3154,3157,3160,3163],[10,11,13],"h2",{"id":12},"a-small-rant","A Small Rant",[15,16,17],"p",{},"At first, it’s just a couple of inputs--no big deal. You sprinkle some useState here and some handleChange function there, and boom! You’ve got yourself a working form. But then, the form grows. More fields. More state. Before you know it you’re manually handling a bunch of validation logic, tracking every keystroke like a detective, and somehow, wondering how you’ve got a headache from trying to implement a form.",[15,19,20,21,25,26,30],{},"How about validation? Some new level of chaos. You write a function to check if an email is valid, another to ensure passwords are strong, and yet another to ensure that no user enters ",[22,23,24],"code",{},"123"," as their first name. Now, you manage to overcome the previous struggles and get to write code for capturing validation errors and displaying them, ",[27,28,29],"em",{},"‘If this field is empty, display this error. If it is not filled correctly, show that error’",".",[15,32,33],{},"By the time you’ve written validation, error handling and submission logic, your form is rerendering so much it might as well have its own loading screen. Because of these extra renders, performance may be compromised for complex forms.\nImagine doing all these for a complex form-one with dropdowns, check boxes, date pickers etc.\nAt this point, your form isn’t just a form--it’s a full time job, and suddenly, you’re questioning your life choices.",[15,35,36],{},"Forms are actually supposed to be simple, but managing them all by yourself in React can feel like assembling new equipment without the manual. But there’s good news, React Hook Form is here to save the day-no more unnecessary state management or rerenders, or wrestling with validation logic. Just smooth easy form handling.",[10,38,40],{"id":39},"what-is-react-hook-form","What is React Hook Form?",[15,42,43],{},"React Hook Form is a library that simplifies form handling in React. It handles form state efficiently, reduces unnecessary re-renders, and makes validation seamless. According to the documentation, it's performant, flexible, and allows you create extensible forms with easy-to-use validation.",[10,45,47],{"id":46},"installation","Installation",[15,49,50],{},"Get started by installing the library using your favorite package manager. I'd be using npm for this guide.",[52,53,58],"pre",{"className":54,"code":55,"language":56,"meta":57,"style":57},"language-bash shiki shiki-themes kanagawa-lotus","npm install react-hook-form\n","bash","",[22,59,60],{"__ignoreMap":57},[61,62,65,69,73],"span",{"class":63,"line":64},"line",1,[61,66,68],{"class":67},"sISTA","npm",[61,70,72],{"class":71},"sKHqS"," install",[61,74,75],{"class":71}," react-hook-form\n",[10,77,79],{"id":78},"the-useform-hook","The useForm Hook",[15,81,82,83,86,87,89,90,93],{},"Meet the ",[22,84,85],{},"useForm"," hook-your new best friend in form management. The ",[27,88,85],{}," hook is the main hook in React Hook Form. It's used to create a form ",[27,91,92],{},"instance"," and manage form state. It does all the heavy lifting for you by:",[95,96,97,111,119],"ul",{},[98,99,100,106,107,110],"li",{},[27,101,102],{},[103,104,105],"strong",{},"automatically tracking the fields in your form",". This means you don’t have to track the values of your field with ",[22,108,109],{},"useState"," as they change.",[98,112,113,118],{},[27,114,115],{},[103,116,117],{},"handling validation like a pro",". Just define rules, and the errors appear when they need to. No more setting form error messages manually.",[98,120,121,126,127,130],{},[27,122,123],{},[103,124,125],{},"making submission easier",". It provides a submit function out of the box that doesn’t submit until all validation logic has passed. And of course, no more ",[22,128,129],{},"e.preventDefault()"," like its 2015.",[15,132,133],{},"Enough talking. Let’s write some code! 💻",[135,136],"br",{},[15,138,139,140,142],{},"Import the ",[27,141,85],{}," hook from the library.",[52,144,148],{"className":145,"code":146,"language":147,"meta":57,"style":57},"language-tsx shiki shiki-themes kanagawa-lotus","import { useForm } from \"react-hook-form\";\n","tsx",[22,149,150],{"__ignoreMap":57},[61,151,152,156,160,164,167,171,174],{"class":63,"line":64},[61,153,155],{"class":154},"sYIP1","import ",[61,157,159],{"class":158},"soh45","{",[61,161,163],{"class":162},"sE3-p"," useForm",[61,165,166],{"class":158}," }",[61,168,170],{"class":169},"spXry"," from",[61,172,173],{"class":71}," \"react-hook-form\"",[61,175,176],{"class":158},";\n",[15,178,179,180,183,184,186],{},"Create a component called ",[22,181,182],{},"SimpleEmailForm",". Then like a regular React hook, call the ",[27,185,85],{}," hook at the top level of your component, and destructure the form instance.",[52,188,192],{"className":189,"code":190,"language":191,"meta":57,"style":57},"language-jsx shiki shiki-themes kanagawa-lotus","const {\n  register,\n  handleSubmit,\n  formState: { errors },\n} = useForm();\n","jsx",[22,193,194,202,211,219,237],{"__ignoreMap":57},[61,195,196,199],{"class":63,"line":64},[61,197,198],{"class":169},"const",[61,200,201],{"class":158}," {\n",[61,203,205,208],{"class":63,"line":204},2,[61,206,207],{"class":162},"  register",[61,209,210],{"class":158},",\n",[61,212,214,217],{"class":63,"line":213},3,[61,215,216],{"class":162},"  handleSubmit",[61,218,210],{"class":158},[61,220,222,225,228,231,234],{"class":63,"line":221},4,[61,223,224],{"class":162},"  formState",[61,226,227],{"class":158},":",[61,229,230],{"class":158}," {",[61,232,233],{"class":162}," errors ",[61,235,236],{"class":158},"},\n",[61,238,240,243,247,250],{"class":63,"line":239},5,[61,241,242],{"class":158},"}",[61,244,246],{"class":245},"sXttF"," =",[61,248,163],{"class":249},"sRuoB",[61,251,252],{"class":158},"();\n",[15,254,255,256,259],{},"Next, let's create a submit handler ",[27,257,258],{},"function",". This is where you'll handle the form data once it's submitted. For now, let's just log the data to the console.",[52,261,263],{"className":189,"code":262,"language":191,"meta":57,"style":57},"const onSubmit = (data) => {\n  console.log(\"Form submitted with data:\", data);\n};\n",[22,264,265,288,313],{"__ignoreMap":57},[61,266,267,269,272,274,277,280,283,286],{"class":63,"line":64},[61,268,198],{"class":169},[61,270,271],{"class":249}," onSubmit",[61,273,246],{"class":245},[61,275,276],{"class":158}," (",[61,278,279],{"class":162},"data",[61,281,282],{"class":158},")",[61,284,285],{"class":169}," =>",[61,287,201],{"class":158},[61,289,290,293,295,298,301,304,307,310],{"class":63,"line":204},[61,291,292],{"class":162},"  console",[61,294,30],{"class":158},[61,296,297],{"class":249},"log",[61,299,300],{"class":158},"(",[61,302,303],{"class":71},"\"Form submitted with data:\"",[61,305,306],{"class":158},",",[61,308,309],{"class":162}," data",[61,311,312],{"class":158},");\n",[61,314,315],{"class":63,"line":213},[61,316,317],{"class":158},"};\n",[10,319,321],{"id":320},"registering-inputs","Registering Inputs",[15,323,324,325,328],{},"In React Hook Form, every input is registered with the ",[22,326,327],{},"register"," function. This function takes a name and returns a reference to the input. Here's is a very basic example.",[52,330,332],{"className":189,"code":331,"language":191,"meta":57,"style":57},"\u003Cinput {...register(\"email\")} \u002F>\n",[22,333,334],{"__ignoreMap":57},[61,335,336,339,342,344,347,349,351,354,357],{"class":63,"line":64},[61,337,338],{"class":158},"\u003C",[61,340,341],{"class":245},"input",[61,343,230],{"class":158},[61,345,346],{"class":245},"...",[61,348,327],{"class":249},[61,350,300],{"class":158},[61,352,353],{"class":71},"\"email\"",[61,355,356],{"class":158},")}",[61,358,359],{"class":158}," \u002F>\n",[15,361,362,363,365],{},"Let's render the complete JSX for now, we'd come back to the ",[27,364,327],{}," function later.",[52,367,369],{"className":189,"code":368,"language":191,"meta":57,"style":57},"\u003Cform onSubmit={handleSubmit(onSubmit)}>\n  \u003Cinput\n    {...register(\"email\", {\n      required: \"Email is required\",\n      pattern: {\n        value: \u002F^[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,}$\u002Fi,\n        message: \"Invalid email address\",\n      },\n    })}\n  \u002F>\n  {errors.email && \u003Cp>{errors.email.message}\u003C\u002Fp>}\n  \u003Cbutton type=\"submit\">Submit\u003C\u002Fbutton>\n\u003C\u002Fform>\n",[22,370,371,396,404,421,433,442,506,519,525,531,537,581,611],{"__ignoreMap":57},[61,372,373,375,378,380,383,385,388,390,393],{"class":63,"line":64},[61,374,338],{"class":158},[61,376,377],{"class":245},"form",[61,379,271],{"class":169},[61,381,382],{"class":245},"=",[61,384,159],{"class":158},[61,386,387],{"class":249},"handleSubmit",[61,389,300],{"class":158},[61,391,392],{"class":162},"onSubmit",[61,394,395],{"class":158},")}>\n",[61,397,398,401],{"class":63,"line":204},[61,399,400],{"class":158},"  \u003C",[61,402,403],{"class":245},"input\n",[61,405,406,409,411,413,415,417,419],{"class":63,"line":213},[61,407,408],{"class":158},"    {",[61,410,346],{"class":245},[61,412,327],{"class":249},[61,414,300],{"class":158},[61,416,353],{"class":71},[61,418,306],{"class":158},[61,420,201],{"class":158},[61,422,423,426,428,431],{"class":63,"line":221},[61,424,425],{"class":169},"      required",[61,427,227],{"class":158},[61,429,430],{"class":71}," \"Email is required\"",[61,432,210],{"class":158},[61,434,435,438,440],{"class":63,"line":239},[61,436,437],{"class":169},"      pattern",[61,439,227],{"class":158},[61,441,201],{"class":158},[61,443,445,448,450,453,456,459,463,466,469,472,474,477,479,481,485,487,490,492,495,498,501,504],{"class":63,"line":444},6,[61,446,447],{"class":169},"        value",[61,449,227],{"class":158},[61,451,452],{"class":71}," \u002F",[61,454,455],{"class":169},"^",[61,457,458],{"class":158},"[",[61,460,462],{"class":461},"sfUOW","A-Z0-9._%+-",[61,464,465],{"class":158},"]",[61,467,468],{"class":245},"+",[61,470,471],{"class":461},"@",[61,473,458],{"class":158},[61,475,476],{"class":461},"A-Z0-9.-",[61,478,465],{"class":158},[61,480,468],{"class":245},[61,482,484],{"class":483},"sQf5B","\\.",[61,486,458],{"class":158},[61,488,489],{"class":461},"A-Z",[61,491,465],{"class":158},[61,493,494],{"class":245},"{2,}",[61,496,497],{"class":169},"$",[61,499,500],{"class":71},"\u002F",[61,502,503],{"class":169},"i",[61,505,210],{"class":158},[61,507,509,512,514,517],{"class":63,"line":508},7,[61,510,511],{"class":169},"        message",[61,513,227],{"class":158},[61,515,516],{"class":71}," \"Invalid email address\"",[61,518,210],{"class":158},[61,520,522],{"class":63,"line":521},8,[61,523,524],{"class":158},"      },\n",[61,526,528],{"class":63,"line":527},9,[61,529,530],{"class":158},"    })}\n",[61,532,534],{"class":63,"line":533},10,[61,535,536],{"class":158},"  \u002F>\n",[61,538,540,543,546,548,551,554,557,559,562,564,566,568,570,573,576,578],{"class":63,"line":539},11,[61,541,542],{"class":158},"  {",[61,544,545],{"class":162},"errors",[61,547,30],{"class":158},[61,549,550],{"class":245},"email",[61,552,553],{"class":245}," &&",[61,555,556],{"class":158}," \u003C",[61,558,15],{"class":245},[61,560,561],{"class":158},">{",[61,563,545],{"class":162},[61,565,30],{"class":158},[61,567,550],{"class":162},[61,569,30],{"class":158},[61,571,572],{"class":245},"message",[61,574,575],{"class":158},"}\u003C\u002F",[61,577,15],{"class":245},[61,579,580],{"class":158},">}\n",[61,582,584,586,589,592,594,597,600,603,606,608],{"class":63,"line":583},12,[61,585,400],{"class":158},[61,587,588],{"class":245},"button",[61,590,591],{"class":169}," type",[61,593,382],{"class":245},[61,595,596],{"class":71},"\"submit\"",[61,598,599],{"class":158},">",[61,601,602],{"class":162},"Submit",[61,604,605],{"class":158},"\u003C\u002F",[61,607,588],{"class":245},[61,609,610],{"class":158},">\n",[61,612,614,616,618],{"class":63,"line":613},13,[61,615,605],{"class":158},[61,617,377],{"class":245},[61,619,610],{"class":158},[15,621,622],{},"Boom! You have created a basic form with React Hook Form and an email input with some validation.",[15,624,625],{},"Here's how your code should look like so far.",[52,627,629],{"className":189,"code":628,"language":191,"meta":57,"style":57},"import { useForm } from \"react-hook-form\";\n\nconst SimpleEmailForm = () => {\n  const {\n    register,\n    handleSubmit,\n    formState: { errors },\n  } = useForm();\n\n  const onSubmit = (data) => console.log(\"Form submitted:\", data);\n\n  return (\n    \u003Cform onSubmit={handleSubmit(onSubmit)}>\n      \u003Cinput\n        {...register(\"email\", {\n          required: \"Email is required\",\n          pattern: {\n            value: \u002F^[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,}$\u002Fi,\n            message: \"Invalid email address\",\n          },\n        })}\n      \u002F>\n      {errors.email && \u003Cp>{errors.email.message}\u003C\u002Fp>}\n\n      \u003Cbutton type=\"submit\">Submit\u003C\u002Fbutton>\n    \u003C\u002Fform>\n  );\n};\n",[22,630,631,647,653,669,676,683,690,703,714,718,752,756,765,786,794,812,824,834,882,894,900,906,912,948,953,976,986,992],{"__ignoreMap":57},[61,632,633,635,637,639,641,643,645],{"class":63,"line":64},[61,634,155],{"class":154},[61,636,159],{"class":158},[61,638,163],{"class":162},[61,640,166],{"class":158},[61,642,170],{"class":169},[61,644,173],{"class":71},[61,646,176],{"class":158},[61,648,649],{"class":63,"line":204},[61,650,652],{"emptyLinePlaceholder":651},true,"\n",[61,654,655,657,660,662,665,667],{"class":63,"line":213},[61,656,198],{"class":169},[61,658,659],{"class":249}," SimpleEmailForm",[61,661,246],{"class":245},[61,663,664],{"class":158}," ()",[61,666,285],{"class":169},[61,668,201],{"class":158},[61,670,671,674],{"class":63,"line":221},[61,672,673],{"class":169},"  const",[61,675,201],{"class":158},[61,677,678,681],{"class":63,"line":239},[61,679,680],{"class":162},"    register",[61,682,210],{"class":158},[61,684,685,688],{"class":63,"line":444},[61,686,687],{"class":162},"    handleSubmit",[61,689,210],{"class":158},[61,691,692,695,697,699,701],{"class":63,"line":508},[61,693,694],{"class":162},"    formState",[61,696,227],{"class":158},[61,698,230],{"class":158},[61,700,233],{"class":162},[61,702,236],{"class":158},[61,704,705,708,710,712],{"class":63,"line":521},[61,706,707],{"class":158},"  }",[61,709,246],{"class":245},[61,711,163],{"class":249},[61,713,252],{"class":158},[61,715,716],{"class":63,"line":527},[61,717,652],{"emptyLinePlaceholder":651},[61,719,720,722,724,726,728,730,732,734,737,739,741,743,746,748,750],{"class":63,"line":533},[61,721,673],{"class":169},[61,723,271],{"class":249},[61,725,246],{"class":245},[61,727,276],{"class":158},[61,729,279],{"class":162},[61,731,282],{"class":158},[61,733,285],{"class":169},[61,735,736],{"class":162}," console",[61,738,30],{"class":158},[61,740,297],{"class":249},[61,742,300],{"class":158},[61,744,745],{"class":71},"\"Form submitted:\"",[61,747,306],{"class":158},[61,749,309],{"class":162},[61,751,312],{"class":158},[61,753,754],{"class":63,"line":539},[61,755,652],{"emptyLinePlaceholder":651},[61,757,758,762],{"class":63,"line":583},[61,759,761],{"class":760},"sqdTv","  return",[61,763,764],{"class":158}," (\n",[61,766,767,770,772,774,776,778,780,782,784],{"class":63,"line":613},[61,768,769],{"class":158},"    \u003C",[61,771,377],{"class":245},[61,773,271],{"class":169},[61,775,382],{"class":245},[61,777,159],{"class":158},[61,779,387],{"class":249},[61,781,300],{"class":158},[61,783,392],{"class":162},[61,785,395],{"class":158},[61,787,789,792],{"class":63,"line":788},14,[61,790,791],{"class":158},"      \u003C",[61,793,403],{"class":245},[61,795,797,800,802,804,806,808,810],{"class":63,"line":796},15,[61,798,799],{"class":158},"        {",[61,801,346],{"class":245},[61,803,327],{"class":249},[61,805,300],{"class":158},[61,807,353],{"class":71},[61,809,306],{"class":158},[61,811,201],{"class":158},[61,813,815,818,820,822],{"class":63,"line":814},16,[61,816,817],{"class":169},"          required",[61,819,227],{"class":158},[61,821,430],{"class":71},[61,823,210],{"class":158},[61,825,827,830,832],{"class":63,"line":826},17,[61,828,829],{"class":169},"          pattern",[61,831,227],{"class":158},[61,833,201],{"class":158},[61,835,837,840,842,844,846,848,850,852,854,856,858,860,862,864,866,868,870,872,874,876,878,880],{"class":63,"line":836},18,[61,838,839],{"class":169},"            value",[61,841,227],{"class":158},[61,843,452],{"class":71},[61,845,455],{"class":169},[61,847,458],{"class":158},[61,849,462],{"class":461},[61,851,465],{"class":158},[61,853,468],{"class":245},[61,855,471],{"class":461},[61,857,458],{"class":158},[61,859,476],{"class":461},[61,861,465],{"class":158},[61,863,468],{"class":245},[61,865,484],{"class":483},[61,867,458],{"class":158},[61,869,489],{"class":461},[61,871,465],{"class":158},[61,873,494],{"class":245},[61,875,497],{"class":169},[61,877,500],{"class":71},[61,879,503],{"class":169},[61,881,210],{"class":158},[61,883,885,888,890,892],{"class":63,"line":884},19,[61,886,887],{"class":169},"            message",[61,889,227],{"class":158},[61,891,516],{"class":71},[61,893,210],{"class":158},[61,895,897],{"class":63,"line":896},20,[61,898,899],{"class":158},"          },\n",[61,901,903],{"class":63,"line":902},21,[61,904,905],{"class":158},"        })}\n",[61,907,909],{"class":63,"line":908},22,[61,910,911],{"class":158},"      \u002F>\n",[61,913,915,918,920,922,924,926,928,930,932,934,936,938,940,942,944,946],{"class":63,"line":914},23,[61,916,917],{"class":158},"      {",[61,919,545],{"class":162},[61,921,30],{"class":158},[61,923,550],{"class":245},[61,925,553],{"class":245},[61,927,556],{"class":158},[61,929,15],{"class":245},[61,931,561],{"class":158},[61,933,545],{"class":162},[61,935,30],{"class":158},[61,937,550],{"class":162},[61,939,30],{"class":158},[61,941,572],{"class":245},[61,943,575],{"class":158},[61,945,15],{"class":245},[61,947,580],{"class":158},[61,949,951],{"class":63,"line":950},24,[61,952,652],{"emptyLinePlaceholder":651},[61,954,956,958,960,962,964,966,968,970,972,974],{"class":63,"line":955},25,[61,957,791],{"class":158},[61,959,588],{"class":245},[61,961,591],{"class":169},[61,963,382],{"class":245},[61,965,596],{"class":71},[61,967,599],{"class":158},[61,969,602],{"class":162},[61,971,605],{"class":158},[61,973,588],{"class":245},[61,975,610],{"class":158},[61,977,979,982,984],{"class":63,"line":978},26,[61,980,981],{"class":158},"    \u003C\u002F",[61,983,377],{"class":245},[61,985,610],{"class":158},[61,987,989],{"class":63,"line":988},27,[61,990,991],{"class":158},"  );\n",[61,993,995],{"class":63,"line":994},28,[61,996,317],{"class":158},[10,998,1000],{"id":999},"whats-going-on","What's Going On? 🕵🏿",[15,1002,1003,1004,1006],{},"I know. All of this syntax is new to you. Let’s break it down step by step. At the top of our component, you invoked the ",[27,1005,85],{}," hook and got some properties from it:",[95,1008,1009,1023,1032],{},[98,1010,1011,1019,1020,1022],{},[1012,1013,1017],"a",{"href":1014,"rel":1015},"https:\u002F\u002Freact-hook-form.com\u002Fdocs\u002Fuseform\u002Fregister",[1016],"nofollow",[22,1018,327],{},": this is simply a method returned by the useForm hook that lets you ",[27,1021,327],{}," an input and apply validation rules to it.",[98,1024,1025,1031],{},[1012,1026,1029],{"href":1027,"rel":1028},"https:\u002F\u002Freact-hook-form.com\u002Fdocs\u002Fuseform\u002Fhandlesubmit",[1016],[22,1030,387],{},": is a special handler from React hook form that intercepts the form submission, validates the field and only calls our onSubmit function if the checks are successful.",[98,1033,1034,1041],{},[1012,1035,1038],{"href":1036,"rel":1037},"https:\u002F\u002Freact-hook-form.com\u002Fdocs\u002Fuseform\u002Fformstate",[1016],[22,1039,1040],{},"formState",": this object contains tons of useful information about the entire state of your form. For now we are focusing on the errors object which helps us retrieve error messages easily. Without this, you would have to manually write logic for storing and updating form errors.",[15,1043,1044,1045,1047],{},"Next, you wrote the ",[27,1046,392],{}," function which is responsible for submitting the data from the form. This is where you normally would send the data to the database or make an API call with. No strange syntax here.",[10,1049,1051,1052,1055],{"id":1050},"why-onsubmithandlesubmitonsubmit","Why ",[22,1053,1054],{},"onSubmit={handleSubmit(onSubmit)}","?",[15,1057,1058],{},"At first glace, I'm sure you must be wondering what magic 🧙🏽‍♂️ is being conjured here:",[52,1060,1062],{"className":189,"code":1061,"language":191,"meta":57,"style":57},"\u003Cform onSubmit={handleSubmit(onSubmit)}>\n",[22,1063,1064],{"__ignoreMap":57},[61,1065,1066,1068,1070,1072,1074,1076,1078,1080,1082],{"class":63,"line":64},[61,1067,338],{"class":158},[61,1069,377],{"class":245},[61,1071,271],{"class":169},[61,1073,382],{"class":245},[61,1075,159],{"class":158},[61,1077,387],{"class":249},[61,1079,300],{"class":158},[61,1081,392],{"class":162},[61,1083,395],{"class":158},[1085,1086,1087],"blockquote",{},[15,1088,1089],{},"An onSubmit inside a handleSubmit, wrapped inside another onSubmit. What’s going on here?",[15,1091,1092],{},"Well, there’s actually a good reason for this. Let’s demystify!",[95,1094,1095,1100,1105],{},[98,1096,1097,1099],{},[22,1098,392],{}," (from the form tag): this is your standard HTML form submission event, remember? Like onClick, onHover etc. Nothing new here.",[98,1101,1102,1104],{},[22,1103,387],{}," (from React Hook Form): now this is something new. This is React Hook Form’s special handler. Right after you submit your form, this handler swings into action by intercepting the form submission, ensures that the form data passes whatever validation rules you have written, and only calls your actual submit function when there are no validation errors. How sweet!",[98,1106,1107,1109],{},[22,1108,392],{}," (our custom function): this is the function you would normally write to process your data-sending it to a backend, or whatever you wish to do with it.",[15,1111,1112,1113,1115,1116,1119,1120,1122,1123,1125,1126,1128],{},"So to briefly summarize, ",[22,1114,387],{}," is like a ",[27,1117,1118],{},"party bouncer",". It only lets valid data get sent to your custom ",[22,1121,392],{}," function. And plus, you don’t have to manually write ",[22,1124,129],{}," to prevent the page from reloading.\nWithout ",[22,1127,387],{},", we would have to manually check if every field got the right data, store any error messages in state, and deal with unnecessary rerenders. With RHF, validation happens first, and only valid submissions get processed-saving us time and effort!",[1085,1130,1131],{},[15,1132,1133,1134,1136,1137,1139],{},"The ",[22,1135,387],{}," function is a special function that intercepts the form submission, validates the field and only calls our ",[22,1138,392],{}," function if the checks are successful.",[15,1141,1142,1143,1145],{},"Without ",[22,1144,387],{},", we would have to manually check if every field got the right data, store any error messages in state, and deal with unnecessary rerenders. With RHF, validation happens first, and only valid submissions get processed-saving us time and effort! Here's how you might write the same form without RHF:",[52,1147,1149],{"className":189,"code":1148,"language":191,"meta":57,"style":57},"export default function FormWithoutRHF() {\n  const [email, setEmail] = useState(\"\");\n  const [error, setError] = useState(\"\");\n\n  const handleChange = (e) => setEmail(e.target.value);\n\n  const handleSubmit = (e) => {\n    e.preventDefault();\n    if (!email) {\n      setError(\"Email is required\");\n    } else {\n      setError(\"\");\n      console.log(email);\n    }\n  };\n\n  return (\n    \u003Cform onSubmit={handleSubmit}>\n      \u003Cinput value={email} onChange={handleChange} \u002F>\n      {error && \u003Cp>{error}\u003C\u002Fp>}\n      \u003Cbutton type=\"submit\">Submit\u003C\u002Fbutton>\n    \u003C\u002Fform>\n  );\n}\n",[22,1150,1151,1170,1198,1224,1228,1264,1268,1287,1299,1315,1327,1337,1347,1362,1367,1372,1376,1382,1399,1430,1454,1476,1484,1488],{"__ignoreMap":57},[61,1152,1153,1156,1159,1162,1165,1168],{"class":63,"line":64},[61,1154,1155],{"class":169},"export",[61,1157,1158],{"class":169}," default",[61,1160,1161],{"class":169}," function",[61,1163,1164],{"class":249}," FormWithoutRHF",[61,1166,1167],{"class":158},"()",[61,1169,201],{"class":158},[61,1171,1172,1174,1177,1179,1181,1184,1186,1188,1191,1193,1196],{"class":63,"line":204},[61,1173,673],{"class":169},[61,1175,1176],{"class":158}," [",[61,1178,550],{"class":162},[61,1180,306],{"class":158},[61,1182,1183],{"class":162}," setEmail",[61,1185,465],{"class":158},[61,1187,246],{"class":245},[61,1189,1190],{"class":249}," useState",[61,1192,300],{"class":158},[61,1194,1195],{"class":71},"\"\"",[61,1197,312],{"class":158},[61,1199,1200,1202,1204,1207,1209,1212,1214,1216,1218,1220,1222],{"class":63,"line":213},[61,1201,673],{"class":169},[61,1203,1176],{"class":158},[61,1205,1206],{"class":162},"error",[61,1208,306],{"class":158},[61,1210,1211],{"class":162}," setError",[61,1213,465],{"class":158},[61,1215,246],{"class":245},[61,1217,1190],{"class":249},[61,1219,300],{"class":158},[61,1221,1195],{"class":71},[61,1223,312],{"class":158},[61,1225,1226],{"class":63,"line":221},[61,1227,652],{"emptyLinePlaceholder":651},[61,1229,1230,1232,1235,1237,1239,1242,1244,1246,1248,1250,1252,1254,1257,1259,1262],{"class":63,"line":239},[61,1231,673],{"class":169},[61,1233,1234],{"class":249}," handleChange",[61,1236,246],{"class":245},[61,1238,276],{"class":158},[61,1240,1241],{"class":162},"e",[61,1243,282],{"class":158},[61,1245,285],{"class":169},[61,1247,1183],{"class":249},[61,1249,300],{"class":158},[61,1251,1241],{"class":162},[61,1253,30],{"class":158},[61,1255,1256],{"class":162},"target",[61,1258,30],{"class":158},[61,1260,1261],{"class":245},"value",[61,1263,312],{"class":158},[61,1265,1266],{"class":63,"line":444},[61,1267,652],{"emptyLinePlaceholder":651},[61,1269,1270,1272,1275,1277,1279,1281,1283,1285],{"class":63,"line":508},[61,1271,673],{"class":169},[61,1273,1274],{"class":249}," handleSubmit",[61,1276,246],{"class":245},[61,1278,276],{"class":158},[61,1280,1241],{"class":162},[61,1282,282],{"class":158},[61,1284,285],{"class":169},[61,1286,201],{"class":158},[61,1288,1289,1292,1294,1297],{"class":63,"line":521},[61,1290,1291],{"class":162},"    e",[61,1293,30],{"class":158},[61,1295,1296],{"class":249},"preventDefault",[61,1298,252],{"class":158},[61,1300,1301,1304,1306,1309,1311,1313],{"class":63,"line":527},[61,1302,1303],{"class":760},"    if",[61,1305,276],{"class":158},[61,1307,1308],{"class":245},"!",[61,1310,550],{"class":162},[61,1312,282],{"class":158},[61,1314,201],{"class":158},[61,1316,1317,1320,1322,1325],{"class":63,"line":533},[61,1318,1319],{"class":249},"      setError",[61,1321,300],{"class":158},[61,1323,1324],{"class":71},"\"Email is required\"",[61,1326,312],{"class":158},[61,1328,1329,1332,1335],{"class":63,"line":539},[61,1330,1331],{"class":158},"    }",[61,1333,1334],{"class":760}," else",[61,1336,201],{"class":158},[61,1338,1339,1341,1343,1345],{"class":63,"line":583},[61,1340,1319],{"class":249},[61,1342,300],{"class":158},[61,1344,1195],{"class":71},[61,1346,312],{"class":158},[61,1348,1349,1352,1354,1356,1358,1360],{"class":63,"line":613},[61,1350,1351],{"class":162},"      console",[61,1353,30],{"class":158},[61,1355,297],{"class":249},[61,1357,300],{"class":158},[61,1359,550],{"class":162},[61,1361,312],{"class":158},[61,1363,1364],{"class":63,"line":788},[61,1365,1366],{"class":158},"    }\n",[61,1368,1369],{"class":63,"line":796},[61,1370,1371],{"class":158},"  };\n",[61,1373,1374],{"class":63,"line":814},[61,1375,652],{"emptyLinePlaceholder":651},[61,1377,1378,1380],{"class":63,"line":826},[61,1379,761],{"class":760},[61,1381,764],{"class":158},[61,1383,1384,1386,1388,1390,1392,1394,1396],{"class":63,"line":836},[61,1385,769],{"class":158},[61,1387,377],{"class":245},[61,1389,271],{"class":169},[61,1391,382],{"class":245},[61,1393,159],{"class":158},[61,1395,387],{"class":162},[61,1397,1398],{"class":158},"}>\n",[61,1400,1401,1403,1405,1408,1410,1412,1414,1416,1419,1421,1423,1426,1428],{"class":63,"line":884},[61,1402,791],{"class":158},[61,1404,341],{"class":245},[61,1406,1407],{"class":169}," value",[61,1409,382],{"class":245},[61,1411,159],{"class":158},[61,1413,550],{"class":162},[61,1415,242],{"class":158},[61,1417,1418],{"class":169}," onChange",[61,1420,382],{"class":245},[61,1422,159],{"class":158},[61,1424,1425],{"class":162},"handleChange",[61,1427,242],{"class":158},[61,1429,359],{"class":158},[61,1431,1432,1434,1437,1440,1442,1444,1446,1448,1450,1452],{"class":63,"line":896},[61,1433,917],{"class":158},[61,1435,1436],{"class":162},"error ",[61,1438,1439],{"class":245},"&&",[61,1441,556],{"class":158},[61,1443,15],{"class":245},[61,1445,561],{"class":158},[61,1447,1206],{"class":162},[61,1449,575],{"class":158},[61,1451,15],{"class":245},[61,1453,580],{"class":158},[61,1455,1456,1458,1460,1462,1464,1466,1468,1470,1472,1474],{"class":63,"line":902},[61,1457,791],{"class":158},[61,1459,588],{"class":245},[61,1461,591],{"class":169},[61,1463,382],{"class":245},[61,1465,596],{"class":71},[61,1467,599],{"class":158},[61,1469,602],{"class":162},[61,1471,605],{"class":158},[61,1473,588],{"class":245},[61,1475,610],{"class":158},[61,1477,1478,1480,1482],{"class":63,"line":908},[61,1479,981],{"class":158},[61,1481,377],{"class":245},[61,1483,610],{"class":158},[61,1485,1486],{"class":63,"line":914},[61,1487,991],{"class":158},[61,1489,1490],{"class":63,"line":950},[61,1491,1492],{"class":158},"}\n",[15,1494,1495],{},"That’s a lot for just one input field. Imagine doing this for more than 10 inputs. With RHF, we turn all that to this:",[52,1497,1499],{"className":189,"code":1498,"language":191,"meta":57,"style":57},"\u003Cinput {...register(\"email\", { required: \"Email is required\" })} \u002F>;\n{\n  errors.email && \u003Cp>{errors.email?.message}\u003C\u002Fp>;\n}\n",[22,1500,1501,1534,1539,1574],{"__ignoreMap":57},[61,1502,1503,1505,1507,1509,1511,1513,1515,1517,1519,1521,1524,1526,1528,1531],{"class":63,"line":64},[61,1504,338],{"class":158},[61,1506,341],{"class":245},[61,1508,230],{"class":158},[61,1510,346],{"class":245},[61,1512,327],{"class":249},[61,1514,300],{"class":158},[61,1516,353],{"class":71},[61,1518,306],{"class":158},[61,1520,230],{"class":158},[61,1522,1523],{"class":169}," required",[61,1525,227],{"class":158},[61,1527,430],{"class":71},[61,1529,1530],{"class":158}," })}",[61,1532,1533],{"class":158}," \u002F>;\n",[61,1535,1536],{"class":63,"line":204},[61,1537,1538],{"class":158},"{\n",[61,1540,1541,1544,1546,1548,1550,1552,1554,1556,1558,1560,1562,1565,1567,1569,1571],{"class":63,"line":213},[61,1542,1543],{"class":162},"  errors",[61,1545,30],{"class":158},[61,1547,550],{"class":245},[61,1549,553],{"class":245},[61,1551,556],{"class":158},[61,1553,15],{"class":245},[61,1555,561],{"class":158},[61,1557,545],{"class":162},[61,1559,30],{"class":158},[61,1561,550],{"class":162},[61,1563,1564],{"class":158},"?.",[61,1566,572],{"class":245},[61,1568,575],{"class":158},[61,1570,15],{"class":245},[61,1572,1573],{"class":158},">;\n",[61,1575,1576],{"class":63,"line":221},[61,1577,1492],{"class":158},[15,1579,1580],{},"This way, we don’t have to worry about how the validation errors would be tracked and updated. RHF does all these under the hood.",[15,1582,1583],{},"If you're using React Hook Form with TypeScript, you might run into this error when trying to display validation messages:",[52,1585,1587],{"className":145,"code":1586,"language":147,"meta":57,"style":57},"Type 'string | FieldError | Merge\u003CFieldError, FieldErrorsImpl\u003Cany>> | undefined' is not assignable to type 'ReactNode'.\n",[22,1588,1589],{"__ignoreMap":57},[61,1590,1591,1594,1597,1600,1603],{"class":63,"line":64},[61,1592,1593],{"class":162},"Type ",[61,1595,1596],{"class":71},"'string | FieldError | Merge\u003CFieldError, FieldErrorsImpl\u003Cany>> | undefined'",[61,1598,1599],{"class":162}," is not assignable to type ",[61,1601,1602],{"class":71},"'ReactNode'",[61,1604,1605],{"class":158},".\n",[15,1607,1608,1609,1612],{},"This is because ",[22,1610,1611],{},"errors.email.message"," is not always a string. It can be a object in some cases, which TypeScript doesn't allow directly inside JSX.",[15,1614,1615,1616,1621],{},"To fix this, you can ",[1012,1617,1620],{"href":1618,"rel":1619},"https:\u002F\u002Fwww.typescriptlang.org\u002Fdocs\u002Fhandbook\u002F2\u002Feveryday-types.html#type-assertions",[1016],"cast"," the error message to a string like this:",[52,1623,1625],{"className":145,"code":1624,"language":147,"meta":57,"style":57},"{\n  errors.email && \u003Cp>{errors.email.message as string}\u003C\u002Fp>;\n}\n",[22,1626,1627,1631,1669],{"__ignoreMap":57},[61,1628,1629],{"class":63,"line":64},[61,1630,1538],{"class":158},[61,1632,1633,1635,1637,1639,1641,1643,1645,1647,1649,1651,1653,1655,1657,1660,1663,1665,1667],{"class":63,"line":204},[61,1634,1543],{"class":162},[61,1636,30],{"class":158},[61,1638,550],{"class":245},[61,1640,553],{"class":245},[61,1642,556],{"class":158},[61,1644,15],{"class":245},[61,1646,561],{"class":158},[61,1648,545],{"class":162},[61,1650,30],{"class":158},[61,1652,550],{"class":162},[61,1654,30],{"class":158},[61,1656,572],{"class":245},[61,1658,1659],{"class":169}," as",[61,1661,1662],{"class":67}," string",[61,1664,575],{"class":158},[61,1666,15],{"class":245},[61,1668,1573],{"class":158},[61,1670,1671],{"class":63,"line":213},[61,1672,1492],{"class":158},[15,1674,1675],{},"You can log the error message to the console to see what it looks like:",[52,1677,1679],{"className":145,"code":1678,"language":147,"meta":57,"style":57},"console.log(errors);\n",[22,1680,1681],{"__ignoreMap":57},[61,1682,1683,1686,1688,1690,1692,1694],{"class":63,"line":64},[61,1684,1685],{"class":162},"console",[61,1687,30],{"class":158},[61,1689,297],{"class":249},[61,1691,300],{"class":158},[61,1693,545],{"class":162},[61,1695,312],{"class":158},[15,1697,1698],{},"This will give you an object with the error message. You can then access the message from the object. For example:",[52,1700,1702],{"className":145,"code":1701,"language":147,"meta":57,"style":57},"console.log(errors.email.message);\n",[22,1703,1704],{"__ignoreMap":57},[61,1705,1706,1708,1710,1712,1714,1716,1718,1720,1722,1724],{"class":63,"line":64},[61,1707,1685],{"class":162},[61,1709,30],{"class":158},[61,1711,297],{"class":249},[61,1713,300],{"class":158},[61,1715,545],{"class":162},[61,1717,30],{"class":158},[61,1719,550],{"class":162},[61,1721,30],{"class":158},[61,1723,572],{"class":245},[61,1725,312],{"class":158},[15,1727,1728],{},"This will give you the error message. You can then display it in your component.",[52,1730,1731],{"className":145,"code":1624,"language":147,"meta":57,"style":57},[22,1732,1733,1737,1773],{"__ignoreMap":57},[61,1734,1735],{"class":63,"line":64},[61,1736,1538],{"class":158},[61,1738,1739,1741,1743,1745,1747,1749,1751,1753,1755,1757,1759,1761,1763,1765,1767,1769,1771],{"class":63,"line":204},[61,1740,1543],{"class":162},[61,1742,30],{"class":158},[61,1744,550],{"class":245},[61,1746,553],{"class":245},[61,1748,556],{"class":158},[61,1750,15],{"class":245},[61,1752,561],{"class":158},[61,1754,545],{"class":162},[61,1756,30],{"class":158},[61,1758,550],{"class":162},[61,1760,30],{"class":158},[61,1762,572],{"class":245},[61,1764,1659],{"class":169},[61,1766,1662],{"class":67},[61,1768,575],{"class":158},[61,1770,15],{"class":245},[61,1772,1573],{"class":158},[61,1774,1775],{"class":63,"line":213},[61,1776,1492],{"class":158},[15,1778,1779],{},"Now try submitting the form without filling the email field. You should see an error message.",[15,1781,1782,1783,1786],{},"If you type in the email field and submit the form, you should see the error message disappear. Even before you submit the form, the error message disappears when you start typing in the email field. On every keystroke, the ",[22,1784,1785],{},"onChange"," event is triggered and the error message is updated.",[15,1788,1789,1790,1793,1794,1796],{},"For an email field, a required validation is not enough. We also need to validate the email format. You can do this by adding a ",[22,1791,1792],{},"pattern"," validation rule. The ",[22,1795,1792],{}," validation rule takes a regular expression as a value. The regular expression is used to validate the email format. If the email does not match the regular expression, the validation will fail and the error message will be displayed.",[52,1798,1800],{"className":145,"code":1799,"language":147,"meta":57,"style":57},"\u003Cinput\n  {...register(\"email\", {\n    required: \"Email is required\",\n    pattern: {\n      value: \u002F^[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,}$\u002Fi,\n      message: \"Invalid email address\",\n    },\n  })}\n\u002F>\n",[22,1801,1802,1808,1824,1835,1844,1891,1902,1907,1912],{"__ignoreMap":57},[61,1803,1804,1806],{"class":63,"line":64},[61,1805,338],{"class":158},[61,1807,403],{"class":245},[61,1809,1810,1812,1814,1816,1818,1820,1822],{"class":63,"line":204},[61,1811,542],{"class":158},[61,1813,346],{"class":245},[61,1815,327],{"class":249},[61,1817,300],{"class":158},[61,1819,353],{"class":71},[61,1821,306],{"class":158},[61,1823,201],{"class":158},[61,1825,1826,1829,1831,1833],{"class":63,"line":213},[61,1827,1828],{"class":169},"    required",[61,1830,227],{"class":158},[61,1832,430],{"class":71},[61,1834,210],{"class":158},[61,1836,1837,1840,1842],{"class":63,"line":221},[61,1838,1839],{"class":169},"    pattern",[61,1841,227],{"class":158},[61,1843,201],{"class":158},[61,1845,1846,1849,1851,1853,1855,1857,1859,1861,1863,1865,1867,1869,1871,1873,1875,1877,1879,1881,1883,1885,1887,1889],{"class":63,"line":239},[61,1847,1848],{"class":169},"      value",[61,1850,227],{"class":158},[61,1852,452],{"class":71},[61,1854,455],{"class":169},[61,1856,458],{"class":158},[61,1858,462],{"class":461},[61,1860,465],{"class":158},[61,1862,468],{"class":245},[61,1864,471],{"class":461},[61,1866,458],{"class":158},[61,1868,476],{"class":461},[61,1870,465],{"class":158},[61,1872,468],{"class":245},[61,1874,484],{"class":483},[61,1876,458],{"class":158},[61,1878,489],{"class":461},[61,1880,465],{"class":158},[61,1882,494],{"class":245},[61,1884,497],{"class":169},[61,1886,500],{"class":71},[61,1888,503],{"class":169},[61,1890,210],{"class":158},[61,1892,1893,1896,1898,1900],{"class":63,"line":444},[61,1894,1895],{"class":169},"      message",[61,1897,227],{"class":158},[61,1899,516],{"class":71},[61,1901,210],{"class":158},[61,1903,1904],{"class":63,"line":508},[61,1905,1906],{"class":158},"    },\n",[61,1908,1909],{"class":63,"line":521},[61,1910,1911],{"class":158},"  })}\n",[61,1913,1914],{"class":63,"line":527},[61,1915,1916],{"class":158},"\u002F>\n",[15,1918,1919,1920,1925],{},"Don't worry about the regular expression. It's a standard email validation regex. You can read more about it ",[1012,1921,1924],{"href":1922,"rel":1923},"https:\u002F\u002Fhtml.spec.whatwg.org\u002Fmultipage\u002Finput.html#valid-e-mail-address",[1016],"here",". You may not really need to use this regex, there are simpleer ways to validate an email using validation libraries like Zod, but that's for another post.",[15,1927,1928],{},"Now, try inputting an invalid email address. You should see an error message.",[15,1930,1931],{},"Notice how React Hook Form knows which error message to display based on the validation rule that failed. If we were to handle this manually, we would have to write a lot of code to achieve this. Like this:",[52,1933,1935],{"className":145,"code":1934,"language":147,"meta":57,"style":57},"const [emailError, setEmailError] = useState(\"\");\nconst [email, setEmail] = useState(\"\");\n\nconst handleEmailChange = (e) => {\n  const email = e.target.value;\n  setEmail(email);\n  if (!email) {\n    \u002F\u002F Check if the email field is empty\n    setEmailError(\"Email is required\");\n  } else if (!email.match(\u002F^[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,}$\u002Fi)) {\n    \u002F\u002F Check if the email is valid\n    setEmailError(\"Invalid email address\");\n  } else {\n    \u002F\u002F If the email is valid, clear the error message\n    setEmailError(\"\");\n  }\n};\n\nreturn (\n  \u003Cform>\n    \u003Cinput value={email} onChange={handleEmailChange} \u002F>\n    {emailError && \u003Cp>{emailError}\u003C\u002Fp>}\n    \u003Cbutton type=\"submit\">Submit\u003C\u002Fbutton>\n  \u003C\u002Fform>\n);\n",[22,1936,1937,1963,1987,1991,2010,2032,2043,2058,2064,2075,2140,2145,2156,2164,2169,2179,2184,2188,2192,2199,2207,2236,2259,2281,2290],{"__ignoreMap":57},[61,1938,1939,1941,1943,1946,1948,1951,1953,1955,1957,1959,1961],{"class":63,"line":64},[61,1940,198],{"class":169},[61,1942,1176],{"class":158},[61,1944,1945],{"class":162},"emailError",[61,1947,306],{"class":158},[61,1949,1950],{"class":162}," setEmailError",[61,1952,465],{"class":158},[61,1954,246],{"class":245},[61,1956,1190],{"class":249},[61,1958,300],{"class":158},[61,1960,1195],{"class":71},[61,1962,312],{"class":158},[61,1964,1965,1967,1969,1971,1973,1975,1977,1979,1981,1983,1985],{"class":63,"line":204},[61,1966,198],{"class":169},[61,1968,1176],{"class":158},[61,1970,550],{"class":162},[61,1972,306],{"class":158},[61,1974,1183],{"class":162},[61,1976,465],{"class":158},[61,1978,246],{"class":245},[61,1980,1190],{"class":249},[61,1982,300],{"class":158},[61,1984,1195],{"class":71},[61,1986,312],{"class":158},[61,1988,1989],{"class":63,"line":213},[61,1990,652],{"emptyLinePlaceholder":651},[61,1992,1993,1995,1998,2000,2002,2004,2006,2008],{"class":63,"line":221},[61,1994,198],{"class":169},[61,1996,1997],{"class":249}," handleEmailChange",[61,1999,246],{"class":245},[61,2001,276],{"class":158},[61,2003,1241],{"class":162},[61,2005,282],{"class":158},[61,2007,285],{"class":169},[61,2009,201],{"class":158},[61,2011,2012,2014,2017,2019,2022,2024,2026,2028,2030],{"class":63,"line":239},[61,2013,673],{"class":169},[61,2015,2016],{"class":162}," email ",[61,2018,382],{"class":245},[61,2020,2021],{"class":162}," e",[61,2023,30],{"class":158},[61,2025,1256],{"class":162},[61,2027,30],{"class":158},[61,2029,1261],{"class":245},[61,2031,176],{"class":158},[61,2033,2034,2037,2039,2041],{"class":63,"line":444},[61,2035,2036],{"class":249},"  setEmail",[61,2038,300],{"class":158},[61,2040,550],{"class":162},[61,2042,312],{"class":158},[61,2044,2045,2048,2050,2052,2054,2056],{"class":63,"line":508},[61,2046,2047],{"class":760},"  if",[61,2049,276],{"class":158},[61,2051,1308],{"class":245},[61,2053,550],{"class":162},[61,2055,282],{"class":158},[61,2057,201],{"class":158},[61,2059,2060],{"class":63,"line":521},[61,2061,2063],{"class":2062},"sHb24","    \u002F\u002F Check if the email field is empty\n",[61,2065,2066,2069,2071,2073],{"class":63,"line":527},[61,2067,2068],{"class":249},"    setEmailError",[61,2070,300],{"class":158},[61,2072,1324],{"class":71},[61,2074,312],{"class":158},[61,2076,2077,2079,2081,2084,2086,2088,2090,2092,2095,2097,2099,2101,2103,2105,2107,2109,2111,2113,2115,2117,2119,2121,2123,2125,2127,2129,2131,2133,2135,2138],{"class":63,"line":533},[61,2078,707],{"class":158},[61,2080,1334],{"class":760},[61,2082,2083],{"class":760}," if",[61,2085,276],{"class":158},[61,2087,1308],{"class":245},[61,2089,550],{"class":162},[61,2091,30],{"class":158},[61,2093,2094],{"class":249},"match",[61,2096,300],{"class":158},[61,2098,500],{"class":71},[61,2100,455],{"class":169},[61,2102,458],{"class":158},[61,2104,462],{"class":461},[61,2106,465],{"class":158},[61,2108,468],{"class":245},[61,2110,471],{"class":461},[61,2112,458],{"class":158},[61,2114,476],{"class":461},[61,2116,465],{"class":158},[61,2118,468],{"class":245},[61,2120,484],{"class":483},[61,2122,458],{"class":158},[61,2124,489],{"class":461},[61,2126,465],{"class":158},[61,2128,494],{"class":245},[61,2130,497],{"class":169},[61,2132,500],{"class":71},[61,2134,503],{"class":169},[61,2136,2137],{"class":158},"))",[61,2139,201],{"class":158},[61,2141,2142],{"class":63,"line":539},[61,2143,2144],{"class":2062},"    \u002F\u002F Check if the email is valid\n",[61,2146,2147,2149,2151,2154],{"class":63,"line":583},[61,2148,2068],{"class":249},[61,2150,300],{"class":158},[61,2152,2153],{"class":71},"\"Invalid email address\"",[61,2155,312],{"class":158},[61,2157,2158,2160,2162],{"class":63,"line":613},[61,2159,707],{"class":158},[61,2161,1334],{"class":760},[61,2163,201],{"class":158},[61,2165,2166],{"class":63,"line":788},[61,2167,2168],{"class":2062},"    \u002F\u002F If the email is valid, clear the error message\n",[61,2170,2171,2173,2175,2177],{"class":63,"line":796},[61,2172,2068],{"class":249},[61,2174,300],{"class":158},[61,2176,1195],{"class":71},[61,2178,312],{"class":158},[61,2180,2181],{"class":63,"line":814},[61,2182,2183],{"class":158},"  }\n",[61,2185,2186],{"class":63,"line":826},[61,2187,317],{"class":158},[61,2189,2190],{"class":63,"line":836},[61,2191,652],{"emptyLinePlaceholder":651},[61,2193,2194,2197],{"class":63,"line":884},[61,2195,2196],{"class":760},"return",[61,2198,764],{"class":158},[61,2200,2201,2203,2205],{"class":63,"line":896},[61,2202,400],{"class":158},[61,2204,377],{"class":245},[61,2206,610],{"class":158},[61,2208,2209,2211,2213,2215,2217,2219,2221,2223,2225,2227,2229,2232,2234],{"class":63,"line":902},[61,2210,769],{"class":158},[61,2212,341],{"class":245},[61,2214,1407],{"class":169},[61,2216,382],{"class":245},[61,2218,159],{"class":158},[61,2220,550],{"class":162},[61,2222,242],{"class":158},[61,2224,1418],{"class":169},[61,2226,382],{"class":245},[61,2228,159],{"class":158},[61,2230,2231],{"class":162},"handleEmailChange",[61,2233,242],{"class":158},[61,2235,359],{"class":158},[61,2237,2238,2240,2243,2245,2247,2249,2251,2253,2255,2257],{"class":63,"line":908},[61,2239,408],{"class":158},[61,2241,2242],{"class":162},"emailError ",[61,2244,1439],{"class":245},[61,2246,556],{"class":158},[61,2248,15],{"class":245},[61,2250,561],{"class":158},[61,2252,1945],{"class":162},[61,2254,575],{"class":158},[61,2256,15],{"class":245},[61,2258,580],{"class":158},[61,2260,2261,2263,2265,2267,2269,2271,2273,2275,2277,2279],{"class":63,"line":914},[61,2262,769],{"class":158},[61,2264,588],{"class":245},[61,2266,591],{"class":169},[61,2268,382],{"class":245},[61,2270,596],{"class":71},[61,2272,599],{"class":158},[61,2274,602],{"class":162},[61,2276,605],{"class":158},[61,2278,588],{"class":245},[61,2280,610],{"class":158},[61,2282,2283,2286,2288],{"class":63,"line":950},[61,2284,2285],{"class":158},"  \u003C\u002F",[61,2287,377],{"class":245},[61,2289,610],{"class":158},[61,2291,2292],{"class":63,"line":955},[61,2293,312],{"class":158},[15,2295,2296],{},"Here, we have to manually check if the email field is empty or if the email is invalid. We also have to manually update the error message. Phew!",[15,2298,2299],{},"With React Hook Form, we don't have to do any of that. We just define the validation rules and the appropriate error message is displayed automatically.",[15,2301,2302],{},"Here's how the code would look if you were to add more validation rules to the email field:",[52,2304,2306],{"className":145,"code":2305,"language":147,"meta":57,"style":57},"\u003Cinput\n  {...register(\"email\", {\n    required: \"Email is required\",\n    pattern: {\n      value: \u002F^[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,}$\u002Fi,\n      message: \"Invalid email address\",\n    },\n    minLength: {\n      value: 5,\n      message: \"Email must be at least 5 characters\",\n    },\n    maxLength: {\n      value: 100,\n      message: \"Email must be less than 100 characters\",\n    },\n  })}\n\u002F>\n",[22,2307,2308,2314,2330,2340,2348,2394,2404,2408,2417,2429,2440,2444,2453,2464,2475,2479,2483],{"__ignoreMap":57},[61,2309,2310,2312],{"class":63,"line":64},[61,2311,338],{"class":158},[61,2313,403],{"class":245},[61,2315,2316,2318,2320,2322,2324,2326,2328],{"class":63,"line":204},[61,2317,542],{"class":158},[61,2319,346],{"class":245},[61,2321,327],{"class":249},[61,2323,300],{"class":158},[61,2325,353],{"class":71},[61,2327,306],{"class":158},[61,2329,201],{"class":158},[61,2331,2332,2334,2336,2338],{"class":63,"line":213},[61,2333,1828],{"class":169},[61,2335,227],{"class":158},[61,2337,430],{"class":71},[61,2339,210],{"class":158},[61,2341,2342,2344,2346],{"class":63,"line":221},[61,2343,1839],{"class":169},[61,2345,227],{"class":158},[61,2347,201],{"class":158},[61,2349,2350,2352,2354,2356,2358,2360,2362,2364,2366,2368,2370,2372,2374,2376,2378,2380,2382,2384,2386,2388,2390,2392],{"class":63,"line":239},[61,2351,1848],{"class":169},[61,2353,227],{"class":158},[61,2355,452],{"class":71},[61,2357,455],{"class":169},[61,2359,458],{"class":158},[61,2361,462],{"class":461},[61,2363,465],{"class":158},[61,2365,468],{"class":245},[61,2367,471],{"class":461},[61,2369,458],{"class":158},[61,2371,476],{"class":461},[61,2373,465],{"class":158},[61,2375,468],{"class":245},[61,2377,484],{"class":483},[61,2379,458],{"class":158},[61,2381,489],{"class":461},[61,2383,465],{"class":158},[61,2385,494],{"class":245},[61,2387,497],{"class":169},[61,2389,500],{"class":71},[61,2391,503],{"class":169},[61,2393,210],{"class":158},[61,2395,2396,2398,2400,2402],{"class":63,"line":444},[61,2397,1895],{"class":169},[61,2399,227],{"class":158},[61,2401,516],{"class":71},[61,2403,210],{"class":158},[61,2405,2406],{"class":63,"line":508},[61,2407,1906],{"class":158},[61,2409,2410,2413,2415],{"class":63,"line":521},[61,2411,2412],{"class":169},"    minLength",[61,2414,227],{"class":158},[61,2416,201],{"class":158},[61,2418,2419,2421,2423,2427],{"class":63,"line":527},[61,2420,1848],{"class":169},[61,2422,227],{"class":158},[61,2424,2426],{"class":2425},"sixyv"," 5",[61,2428,210],{"class":158},[61,2430,2431,2433,2435,2438],{"class":63,"line":533},[61,2432,1895],{"class":169},[61,2434,227],{"class":158},[61,2436,2437],{"class":71}," \"Email must be at least 5 characters\"",[61,2439,210],{"class":158},[61,2441,2442],{"class":63,"line":539},[61,2443,1906],{"class":158},[61,2445,2446,2449,2451],{"class":63,"line":583},[61,2447,2448],{"class":169},"    maxLength",[61,2450,227],{"class":158},[61,2452,201],{"class":158},[61,2454,2455,2457,2459,2462],{"class":63,"line":613},[61,2456,1848],{"class":169},[61,2458,227],{"class":158},[61,2460,2461],{"class":2425}," 100",[61,2463,210],{"class":158},[61,2465,2466,2468,2470,2473],{"class":63,"line":788},[61,2467,1895],{"class":169},[61,2469,227],{"class":158},[61,2471,2472],{"class":71}," \"Email must be less than 100 characters\"",[61,2474,210],{"class":158},[61,2476,2477],{"class":63,"line":796},[61,2478,1906],{"class":158},[61,2480,2481],{"class":63,"line":814},[61,2482,1911],{"class":158},[61,2484,2485],{"class":63,"line":826},[61,2486,1916],{"class":158},[15,2488,2489,2490,2494],{},"To see the other validation rules React Hook Form supports, you can read about them ",[1012,2491,1924],{"href":2492,"rel":2493},"https:\u002F\u002Freact-hook-form.com\u002Fget-started#Applyvalidation",[1016]," in the documentation.",[15,2496,2497],{},"There’s one more thing we haven’t really talked about. 👀",[10,2499,2501],{"id":2500},"the-secret-sauce-behind-register","The Secret Sauce behind register(...) 🍾",[15,2503,2504,2505,2507],{},"** Note that for simplicity, I didn't include the ",[22,2506,1792],{}," validation rule in the example above. You can add it just like the other validation rules.",[15,2509,2510],{},"So what’s this all about:",[52,2512,2514],{"className":189,"code":2513,"language":191,"meta":57,"style":57},"\u003Cinput {...register(\"email\", { required: \"Email is required\" })} \u002F>\n",[22,2515,2516],{"__ignoreMap":57},[61,2517,2518,2520,2522,2524,2526,2528,2530,2532,2534,2536,2538,2540,2542,2544],{"class":63,"line":64},[61,2519,338],{"class":158},[61,2521,341],{"class":245},[61,2523,230],{"class":158},[61,2525,346],{"class":245},[61,2527,327],{"class":249},[61,2529,300],{"class":158},[61,2531,353],{"class":71},[61,2533,306],{"class":158},[61,2535,230],{"class":158},[61,2537,1523],{"class":169},[61,2539,227],{"class":158},[61,2541,430],{"class":71},[61,2543,1530],{"class":158},[61,2545,359],{"class":158},[15,2547,2548],{},"Let’s break down our code again.",[95,2550,2551,2557],{},[98,2552,2553,2556],{},[22,2554,2555],{},"register(name: string, options?: RegisterOptions)",": Like I described earlier, this is a method returned by the useForm hook. By doing this, we’re saying: “Hey, track this field called email”. It takes two parameters, a string, and an optional options object. The first parameter describes the input’s name, and the second describes the input’s behaviour.",[98,2558,2559,2560,2563],{},"The options object ",[22,2561,2562],{},"{ required: \"Email is required\" }"," is where you would define all the validation rules, that is, how the input behaves. You can add other basic validation rules from HTML min, max, minLength, maxLength, pattern, and validate.",[15,2565,2566,2567,2570,2571,2570,2574,2577,2578,2581],{},"As an example, to register ",[27,2568,2569],{},"first name",", ",[27,2572,2573],{},"age",[27,2575,2576],{},"password"," and a ",[27,2579,2580],{},"checkbox field",", you would do something like this:",[52,2583,2585],{"className":189,"code":2584,"language":191,"meta":57,"style":57},"\u003Cform onSubmit={handleSubmit(onSubmit)}>\n  \u003Cinput {...register(\"firstName\", { required: true, maxLength: 20 })} \u002F>\n\n  \u003Cinput type=\"number\" {...register(\"age\", { min: 18, max: 99 })} \u002F>\n\n  \u003Cinput\n    type=\"password\"\n    {...register(\"password\", { required: true, minLength: 6 })}\n  \u002F>\n\n  \u003Clabel>\n    \u003Cinput type=\"checkbox\" {...register(\"terms\", { required: true })} \u002F>I agree\n    to the terms and conditions\n  \u003C\u002Flabel>\n\n  \u003Cbutton type=\"submit\">Submit\u003C\u002Fbutton>\n\u003C\u002Fform>\n",[22,2586,2587,2607,2649,2653,2703,2707,2713,2723,2759,2763,2767,2776,2818,2823,2831,2835,2857],{"__ignoreMap":57},[61,2588,2589,2591,2593,2595,2597,2599,2601,2603,2605],{"class":63,"line":64},[61,2590,338],{"class":158},[61,2592,377],{"class":245},[61,2594,271],{"class":169},[61,2596,382],{"class":245},[61,2598,159],{"class":158},[61,2600,387],{"class":249},[61,2602,300],{"class":158},[61,2604,392],{"class":162},[61,2606,395],{"class":158},[61,2608,2609,2611,2613,2615,2617,2619,2621,2624,2626,2628,2630,2632,2635,2637,2640,2642,2645,2647],{"class":63,"line":204},[61,2610,400],{"class":158},[61,2612,341],{"class":245},[61,2614,230],{"class":158},[61,2616,346],{"class":245},[61,2618,327],{"class":249},[61,2620,300],{"class":158},[61,2622,2623],{"class":71},"\"firstName\"",[61,2625,306],{"class":158},[61,2627,230],{"class":158},[61,2629,1523],{"class":169},[61,2631,227],{"class":158},[61,2633,2634],{"class":154}," true",[61,2636,306],{"class":158},[61,2638,2639],{"class":169}," maxLength",[61,2641,227],{"class":158},[61,2643,2644],{"class":2425}," 20",[61,2646,1530],{"class":158},[61,2648,359],{"class":158},[61,2650,2651],{"class":63,"line":213},[61,2652,652],{"emptyLinePlaceholder":651},[61,2654,2655,2657,2659,2661,2663,2666,2668,2670,2672,2674,2677,2679,2681,2684,2686,2689,2691,2694,2696,2699,2701],{"class":63,"line":221},[61,2656,400],{"class":158},[61,2658,341],{"class":245},[61,2660,591],{"class":169},[61,2662,382],{"class":245},[61,2664,2665],{"class":71},"\"number\"",[61,2667,230],{"class":158},[61,2669,346],{"class":245},[61,2671,327],{"class":249},[61,2673,300],{"class":158},[61,2675,2676],{"class":71},"\"age\"",[61,2678,306],{"class":158},[61,2680,230],{"class":158},[61,2682,2683],{"class":169}," min",[61,2685,227],{"class":158},[61,2687,2688],{"class":2425}," 18",[61,2690,306],{"class":158},[61,2692,2693],{"class":169}," max",[61,2695,227],{"class":158},[61,2697,2698],{"class":2425}," 99",[61,2700,1530],{"class":158},[61,2702,359],{"class":158},[61,2704,2705],{"class":63,"line":239},[61,2706,652],{"emptyLinePlaceholder":651},[61,2708,2709,2711],{"class":63,"line":444},[61,2710,400],{"class":158},[61,2712,403],{"class":245},[61,2714,2715,2718,2720],{"class":63,"line":508},[61,2716,2717],{"class":169},"    type",[61,2719,382],{"class":245},[61,2721,2722],{"class":71},"\"password\"\n",[61,2724,2725,2727,2729,2731,2733,2736,2738,2740,2742,2744,2746,2748,2751,2753,2756],{"class":63,"line":521},[61,2726,408],{"class":158},[61,2728,346],{"class":245},[61,2730,327],{"class":249},[61,2732,300],{"class":158},[61,2734,2735],{"class":71},"\"password\"",[61,2737,306],{"class":158},[61,2739,230],{"class":158},[61,2741,1523],{"class":169},[61,2743,227],{"class":158},[61,2745,2634],{"class":154},[61,2747,306],{"class":158},[61,2749,2750],{"class":169}," minLength",[61,2752,227],{"class":158},[61,2754,2755],{"class":2425}," 6",[61,2757,2758],{"class":158}," })}\n",[61,2760,2761],{"class":63,"line":527},[61,2762,536],{"class":158},[61,2764,2765],{"class":63,"line":533},[61,2766,652],{"emptyLinePlaceholder":651},[61,2768,2769,2771,2774],{"class":63,"line":539},[61,2770,400],{"class":158},[61,2772,2773],{"class":245},"label",[61,2775,610],{"class":158},[61,2777,2778,2780,2782,2784,2786,2789,2791,2793,2795,2797,2800,2802,2804,2806,2808,2810,2812,2815],{"class":63,"line":583},[61,2779,769],{"class":158},[61,2781,341],{"class":245},[61,2783,591],{"class":169},[61,2785,382],{"class":245},[61,2787,2788],{"class":71},"\"checkbox\"",[61,2790,230],{"class":158},[61,2792,346],{"class":245},[61,2794,327],{"class":249},[61,2796,300],{"class":158},[61,2798,2799],{"class":71},"\"terms\"",[61,2801,306],{"class":158},[61,2803,230],{"class":158},[61,2805,1523],{"class":169},[61,2807,227],{"class":158},[61,2809,2634],{"class":154},[61,2811,1530],{"class":158},[61,2813,2814],{"class":158}," \u002F>",[61,2816,2817],{"class":162},"I agree\n",[61,2819,2820],{"class":63,"line":613},[61,2821,2822],{"class":162},"    to the terms and conditions\n",[61,2824,2825,2827,2829],{"class":63,"line":788},[61,2826,2285],{"class":158},[61,2828,2773],{"class":245},[61,2830,610],{"class":158},[61,2832,2833],{"class":63,"line":796},[61,2834,652],{"emptyLinePlaceholder":651},[61,2836,2837,2839,2841,2843,2845,2847,2849,2851,2853,2855],{"class":63,"line":814},[61,2838,400],{"class":158},[61,2840,588],{"class":245},[61,2842,591],{"class":169},[61,2844,382],{"class":245},[61,2846,596],{"class":71},[61,2848,599],{"class":158},[61,2850,602],{"class":162},[61,2852,605],{"class":158},[61,2854,588],{"class":245},[61,2856,610],{"class":158},[61,2858,2859,2861,2863],{"class":63,"line":826},[61,2860,605],{"class":158},[61,2862,377],{"class":245},[61,2864,610],{"class":158},[15,2866,2867,2868,227],{},"This code ",[27,2869,2870],{},"registers",[95,2872,2873,2879,2885,2890],{},[98,2874,2875,2876,2878],{},"A ",[27,2877,2569],{}," field which must be filled and has a maximum length of 20",[98,2880,2881,2882,2884],{},"An ",[27,2883,2573],{}," field that must be between 18 and 99",[98,2886,2875,2887,2889],{},[27,2888,2576],{}," field that ensures that the user provides at least 6 characters",[98,2891,2892,2893,2896],{},"And a ",[27,2894,2895],{},"checkbox"," that mandates the user to agree before submitting",[10,2898,2900],{"id":2899},"whats-really-inside-register","What’s Really Inside register()?",[15,2902,2903],{},"This register function exposes the values of all the inputs to the useForm hook for form validation and submission. When you call register(‘firstname’), it’s not just a magic function-it’s actually returning a set of useful props that React Hook Form uses to track the input field. Instead of spreading these props directly inside the input like this:",[52,2905,2906],{"className":189,"code":2513,"language":191,"meta":57,"style":57},[22,2907,2908],{"__ignoreMap":57},[61,2909,2910,2912,2914,2916,2918,2920,2922,2924,2926,2928,2930,2932,2934,2936],{"class":63,"line":64},[61,2911,338],{"class":158},[61,2913,341],{"class":245},[61,2915,230],{"class":158},[61,2917,346],{"class":245},[61,2919,327],{"class":249},[61,2921,300],{"class":158},[61,2923,353],{"class":71},[61,2925,306],{"class":158},[61,2927,230],{"class":158},[61,2929,1523],{"class":169},[61,2931,227],{"class":158},[61,2933,430],{"class":71},[61,2935,1530],{"class":158},[61,2937,359],{"class":158},[15,2939,2940],{},"You can destructure them manually like this:",[52,2942,2944],{"className":189,"code":2943,"language":191,"meta":57,"style":57},"\u002F\u002F Destructure the props\nconst { onChange, onBlur, name, ref } = register(\"email\", {\n  required: \"Email is required\",\n});\n\n\u002F\u002F Use the props directly in the input\n\u003Cinput\n  onChange={onChange} \u002F\u002F assign onChange event\n  onBlur={onBlur} \u002F\u002F assign onBlur event\n  name={name} \u002F\u002F assign name prop\n  ref={ref} \u002F\u002F assign ref prop\n\u002F>;\n",[22,2945,2946,2951,2989,3000,3005,3009,3014,3020,3036,3053,3070,3087],{"__ignoreMap":57},[61,2947,2948],{"class":63,"line":64},[61,2949,2950],{"class":2062},"\u002F\u002F Destructure the props\n",[61,2952,2953,2955,2957,2959,2961,2964,2966,2969,2971,2974,2976,2978,2981,2983,2985,2987],{"class":63,"line":204},[61,2954,198],{"class":169},[61,2956,230],{"class":158},[61,2958,1418],{"class":162},[61,2960,306],{"class":158},[61,2962,2963],{"class":162}," onBlur",[61,2965,306],{"class":158},[61,2967,2968],{"class":162}," name",[61,2970,306],{"class":158},[61,2972,2973],{"class":162}," ref ",[61,2975,242],{"class":158},[61,2977,246],{"class":245},[61,2979,2980],{"class":249}," register",[61,2982,300],{"class":158},[61,2984,353],{"class":71},[61,2986,306],{"class":158},[61,2988,201],{"class":158},[61,2990,2991,2994,2996,2998],{"class":63,"line":213},[61,2992,2993],{"class":162},"  required",[61,2995,227],{"class":158},[61,2997,430],{"class":71},[61,2999,210],{"class":158},[61,3001,3002],{"class":63,"line":221},[61,3003,3004],{"class":158},"});\n",[61,3006,3007],{"class":63,"line":239},[61,3008,652],{"emptyLinePlaceholder":651},[61,3010,3011],{"class":63,"line":444},[61,3012,3013],{"class":2062},"\u002F\u002F Use the props directly in the input\n",[61,3015,3016,3018],{"class":63,"line":508},[61,3017,338],{"class":158},[61,3019,403],{"class":245},[61,3021,3022,3025,3027,3029,3031,3033],{"class":63,"line":521},[61,3023,3024],{"class":169},"  onChange",[61,3026,382],{"class":245},[61,3028,159],{"class":158},[61,3030,1785],{"class":162},[61,3032,242],{"class":158},[61,3034,3035],{"class":2062}," \u002F\u002F assign onChange event\n",[61,3037,3038,3041,3043,3045,3048,3050],{"class":63,"line":527},[61,3039,3040],{"class":169},"  onBlur",[61,3042,382],{"class":245},[61,3044,159],{"class":158},[61,3046,3047],{"class":162},"onBlur",[61,3049,242],{"class":158},[61,3051,3052],{"class":2062}," \u002F\u002F assign onBlur event\n",[61,3054,3055,3058,3060,3062,3065,3067],{"class":63,"line":533},[61,3056,3057],{"class":169},"  name",[61,3059,382],{"class":245},[61,3061,159],{"class":158},[61,3063,3064],{"class":162},"name",[61,3066,242],{"class":158},[61,3068,3069],{"class":2062}," \u002F\u002F assign name prop\n",[61,3071,3072,3075,3077,3079,3082,3084],{"class":63,"line":539},[61,3073,3074],{"class":169},"  ref",[61,3076,382],{"class":245},[61,3078,159],{"class":158},[61,3080,3081],{"class":162},"ref",[61,3083,242],{"class":158},[61,3085,3086],{"class":2062}," \u002F\u002F assign ref prop\n",[61,3088,3089],{"class":63,"line":583},[61,3090,3091],{"class":158},"\u002F>;\n",[15,3093,1133,3094,3096],{},[27,3095,327],{}," function returns an object containing:",[95,3098,3099,3104,3109,3114],{},[98,3100,3101,3103],{},[22,3102,1785],{},": which updates the form state when the input value changes",[98,3105,3106,3108],{},[22,3107,3047],{},": which triggers validation when the input loses focus",[98,3110,3111,3113],{},[22,3112,3064],{},": which assigns the field name",[98,3115,3116,3118],{},[22,3117,3081],{},": which connects the input to RHF for tracking",[15,3120,3121,3122,3125,3126,3129],{},"The shorthand ",[22,3123,3124],{},"{...register(\"firstName\", {...rules})}"," is just a more compact and cleaner way to apply everything at once, rather than assign each prop manually. Both methods work the same way but the shorthand keeps things ",[27,3127,3128],{},"DRY",". I just needed to show you the second approach to help you understand what’s going on under the hood.",[10,3131,3133],{"id":3132},"tying-it-all-together","Tying it All Together",[15,3135,3136],{},"Form management in React doesn’t have to be a headache, trust me! Instead of drowning in manually tracking errors, and wondering what’s causing your form to rerender, React Hook Form gives us a cleaner, simpler, and more efficient way to handle forms.",[15,3138,3139],{},"Here’s what we covered:",[95,3141,3142,3145,3148,3151],{},[98,3143,3144],{},"Why form management in React can be tricky",[98,3146,3147],{},"How useForm simplifies state management and validation",[98,3149,3150],{},"Understanding what handleSubmit, register is doing under the hood",[98,3152,3153],{},"A variety of real world input fields with native HTML validation",[15,3155,3156],{},"At the end of the day, RHF takes the heavy lifting off our shoulders, letting us focus on building great experiences instead of debugging form logic.",[15,3158,3159],{},"Thanks for reading! May your forms be smooth, your errors be few, and your\nre-renders be minimal.",[15,3161,3162],{},"See you in the next one!",[3164,3165,3166],"style",{},"html pre.shiki code .spXry, html code.shiki .spXry{--shiki-default:#624C83}html pre.shiki code .soh45, html code.shiki .soh45{--shiki-default:#4E8CA2}html pre.shiki code .sE3-p, html code.shiki .sE3-p{--shiki-default:#545464}html pre.shiki code .sXttF, html code.shiki .sXttF{--shiki-default:#77713F}html pre.shiki code .sRuoB, html code.shiki .sRuoB{--shiki-default:#4D699B}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 pre.shiki code .sKHqS, html code.shiki .sKHqS{--shiki-default:#6F894E}html pre.shiki code .sfUOW, html code.shiki .sfUOW{--shiki-default:#836F4A}html pre.shiki code .sQf5B, html code.shiki .sQf5B{--shiki-default:#6693BF}html pre.shiki code .sYIP1, html code.shiki .sYIP1{--shiki-default:#CC6D00}html pre.shiki code .sqdTv, html code.shiki .sqdTv{--shiki-default:#624C83;--shiki-default-font-weight:bold}html pre.shiki code .sixyv, html code.shiki .sixyv{--shiki-default:#B35B79}html pre.shiki code .sHb24, html code.shiki .sHb24{--shiki-default:#716E61}html pre.shiki code .sISTA, html code.shiki .sISTA{--shiki-default:#597B75}",{"title":57,"searchDepth":204,"depth":204,"links":3168},[3169,3170,3171,3172,3173,3174,3175,3177,3178,3179],{"id":12,"depth":204,"text":13},{"id":39,"depth":204,"text":40},{"id":46,"depth":204,"text":47},{"id":78,"depth":204,"text":79},{"id":320,"depth":204,"text":321},{"id":999,"depth":204,"text":1000},{"id":1050,"depth":204,"text":3176},"Why onSubmit={handleSubmit(onSubmit)}?",{"id":2500,"depth":204,"text":2501},{"id":2899,"depth":204,"text":2900},{"id":3132,"depth":204,"text":3133},"2025-03-16","Manually creating React forms can collapse under state, validation and rerenders. Here's how React Hook Form comes to the rescue.",false,"md",{},"\u002Fposts\u002Fforms-without-the-stress",{"title":5,"description":3181},"posts\u002Fforms-without-the-stress",null,[3190,3191],"react","guides","YTWn67BmTbw7B0zFRn797yqt6oaQ84MWDjIV3HqlTbs",[3194,3198,3202,3206,3210,3214,3218,3222,3223,3227],{"path":3195,"title":3196,"date":3197},"\u002Fposts\u002Ffunctional-options-may-not-always-form-closures","Functional options may not always form closures","2026-10-06",{"path":3199,"title":3200,"date":3201},"\u002Fposts\u002Fgo-closures-functional-options-pattern","Understanding closures in Go through the functional options pattern","2026-09-25",{"path":3203,"title":3204,"date":3205},"\u002Fposts\u002Fgoing-with-go","Going with Go","2026-09-14",{"path":3207,"title":3208,"date":3209},"\u002Fposts\u002Fcollecting-blogs","Collecting blogs","2026-09-10",{"path":3211,"title":3212,"date":3213},"\u002Fposts\u002Fhello-world","Hello, world!","2026-08-01",{"path":3215,"title":3216,"date":3217},"\u002Fposts\u002Fwhy-my-first-react-app-should-have-been-tic-tac-toe","Why my first React app should have been tic-tac-toe","2025-07-02",{"path":3219,"title":3220,"date":3221},"\u002Fposts\u002Ftyped-and-tested","Typed and tested","2025-05-29",{"path":3185,"title":5,"date":3180},{"path":3224,"title":3225,"date":3226},"\u002Fposts\u002Fdata-fetching","Data fetching in React","2025-01-26",{"path":3228,"title":3229,"date":3230},"\u002Fposts\u002F2024-in-review","2024 in review as a frontend engineer","2024-12-31",1791245350748]