Next JS forms with Shadcn UI (the EASY way)

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
in this video we're going to take a look at how we can validate forms with shad CN UI and Zod for form validation within a nexj S14 project now this is the small form we're going to be building I've built upon the examples that Shaden UI have in their documentation but I've added a little bit of more complexity to this example so we can see we've got a bunch of form field Sim if we try and hit submit obviously we get displayed with a bunch of error messages if we fill out this form then to get rid of these error messages let's add an account type as well let's add a personal account type let's hit submit now and we can see that we also have a password confirm validation so we can see that these passwords don't match let's start typing in the password the same password there we go we have a valid password confirmed but also we've got a little bit more of complexity here with the account type so if we select a company account type then we have some additional validation we have an addition field called company name so we try and hit submit when our account type is set to company but we don't have a company name we also need to fill in this field as well so it may seem a little bit basic but we are covering a little bit of complexity and a couple of different use cases so let's get right into it then now I've already got a blank next js14 project up and running and I've already installed shadsy nuui from here all we're going to do is add our form to the homepage so we're going to turn this page as well into a client component so we need to add use client at the top here because we have to have our forms render in a client component because it depends on things like react Hooks and context and things like that so browser specific apis from here let's refer to the Shaden UI documentation for forms so Shaden uses react hook form to handle building out forms and it also contains some form components that we can use additionally Shaden uses Zod for form validation so if we scroll down to the form documentation we scroll all the way down we want to scroll down to the installation we want to install MPX Shad CN UI at latest add form so let's copy this command and paste it in our terminal to install everything to do with forms for Shad CN UI from here we need to create our form definition using react H form so at the top here let's we need to import all as Zod from Zod so Zod remember is handling our form validation and we need to import use hook or sorry use form from react hook form so let's import use form from react hook form additionally we need to import the Zod resolver from at hook form resolvers Zod now this sod resolver is going to to hook into the react hook form and anytime our form data changes it's going to revalidate that data based on the rules we provide in our Zod configuration for our form so first of all we need to create a form schema which will Define all of the properties and the property types and the validation for our form so to do that we can at the top here go cons form schema and set this equal to we need to use Zod here however common practice here is to import all as Zed from Zod this sounds a bit weird and if you're American you're probably laughing at that but we need to import all a zed from Zod here it doesn't matter if we call it import all as Zod from Zod but all across the documentation for Zod everyone Imports it as Zed from Zod so then we can use Zed doob so we're saying here our form data is an object and on this object we're going to have a bunch of fields so first of all let's start off with an email address so we're going to to set this equal to z. string so this ISS built-in from Zod so whenever we're calling this string function here we're telling the form schema that email address is of type string additionally we can use the email function so this is saying that this is of type string but also it has to conform to or has to be a valid email address so we don't have to set up any configuration for this this comes out of the box with Zod so it's automatically going to validate if this email address is a valid email or not now before we add any more Fields I think it makes sense that we add our form and just test out to see if this form schema and our form validation is actually all working correctly So within our home function then let's create a con form and set this equal to use form now because we're using typescript here we need to tell the use form hook the field values and their types so to do that because use form is a generic function we can pass a type to to it now the type we need to pass to the use form Hook is z. infer and again this z. infer is also a generic so we can pass a type to this and we want to add here type of and reference our form schema const so all this is going to do is essentially map all of our fields and types of those fields to our use form Hook from our schema so we're inferring the type of our form based on our form schema now next we need to pass in a configuration object to our Ed form hook the first we need to pass is a resolver and we need to set this equal to Zod resolver which we're importing at the top here from at hook form resolvers Zod and we just need to pass in our form schema now what this is going to do is the Zod resolver is going to take our form schema and it's going to map remember the reactor form and Zod know nothing about each other but this Zod resolver is going to link the two so what it's going to happen is the Zod resolver is going to take our form schema and anytime our data changes it's going to revalidate that data based on our form schema and based on the validation rules we pass to our form schema obviously at the moment we just have an email address we're saying it's a typ string and it's an email from here there's one last thing we need to do to our use form hook and that is add some default values now we need to add some default values here and we want to add an email address just set equal to an empty string so from here then all we need to do is add our form markup So within our main tag here we want to render the form component from at/ components uiform so this is coming from Shad CN now we need to pass to this form component all the values that get returned from Ed form as props so to do that we can use the spread operator and just spread form in as all of the props to the form component within here then we need to add a form tag and let's add at the top here let's add a const handle submit and for now let's just add an empty Arrow function the handle submit here we're going to set this equal to on our form on our form on submit however we need to pass to our on submit here the form do on handle submit so it's coming from the form object that gets returned from use form so react hook form is going to take care of the submission of this form but we want to pass in our submit Handler obviously we need to tap into this submit Handler anytime the form was submitted now what's going to happen is anytime our form is invalid our handle submit function is not going to execute it's not going to fire so our handle submit will only run when our form is valid so all of this is handled by the setup we've just done now using the react hook form and Zod with that said within our form we need to add some inputs to do that we need to add a form field component which we can import at the top here from at/ components uiform again this is coming from Shaden UI now we need to add a name to this form field and the name needs to be equal to whichever value we specified in our form schema so this particular form field is going to be the email address so we have to call it email address now there is one pop we can pass to form field called control and if we set this equal to form. control then we'll get some nice and tense on our name so now we can see we're getting an error on name and that is because we need to specify a valid value that comes from our form schema and of course at the moment we only have email address we can see this coming up in our Intellis sense if we didn't have this control prop set then we wouldn't get this nice and Tellis sense so make sure you've got the control prop set and let's select email address for this form field finally for this form field all we need to add is a render prop so let's add a render prop and the render prop will be passed a callback function and as part of the first argument to this callback function it will receive a Field property now we need to return some markup from this render prop so in here let's return a form item which we can import at the top of our file here from at/ component uiform again this comes from Shaden UI now the reason we want a form item here is because it contains react context so anytime we have some error messages and things like that then it's going to be part of this react context in our form item but then any items or any components we render within the form item will have access to that context so for example if we want to display an error message all we need to render is the form message component and again we need to import that at the top here from at/ component and again this is coming from Shad zenui now because we've rendered this form item anytime we get an error for our email address because this is using react context under the hood the form message will automatically display that error message for this field so we don't need to do any more setup other than this however with that said we do need to actually render some sort of input component above any error messages that we may have first of all though let's add a form label and again this is coming from shads Andi and we're going to set this equal to email address and don't forget to import the form label at the top here from @/ compon /i/ form then underneath the form label we want to render a form control now the reason we want to render this form control is because it adds anytime we have error messages for our forms or validation errors for our form Fields this form control will add the appropriate area labels to our input and we're going to render the input within this form control now we don't have to render this form control this is entirely optional however I high highly recommend that you do because then this form control will automatically set the appropriate area labels anytime there's a validation error with this input so then finally all we need to do is render an input component however the input component doesn't get installed as part of the form from Shad CN UI so we need to install that separately so if we head on back to Shad CN UI let's scroll down to input here in the components and we want to go to installation we want to copy the installation script so it's npx Shad CN UI at latest add input let's head on back to our code let's paste it in our terminal then we should have access now to an input component which we need to UT from @/ component uiinput and I'm getting an error here for form control because I haven't actually imported it need to import form control at the top of our file as well so for this input we're going to need to spread the field sorry not the form the field so this field here we need to spread into this input component and we can also add a placeholder if you want to I'm going to call it email address and we can add a type if we want to and set it to type email however if we save this now this all should work so if we run npm run Dev in the terminal and take a look at Local Host 3000 in the browser there we go we can see we have our email address we don't have a submit button yet but if we hit enter in the email address we can see we have invalid email so first of all let's add our submit button so it's a bit easier to see what going on when we submit the form and also I'm just going to increase the form width slightly so quickly back in our code before we add our next form fields on our form tag here let's just add a couple class names I'm going to add a Max width of something like MD and a width of full then we need to add a button at the bottom of this form and I believe that Shaden UI whenever you install Shad CN UI it automatically adds this button component so we don't have to add it manually ually like all the rest of the components from shaten UI however with that said we need to import button from @/ components /i/ button and this button we need to pass a type of submit and the button text will say submit additionally I'm going to add some class names to our button I want it full width so let's go width full here and let's add some spacing between each of our form elements so on our form I'm going to display Flex we're going to have a flex call and a gap of something like four so if we save this and take a look in the browser now there we go this is looking a lot nicer let's hit submit and there we go our validation error is working as expected from here then let's add our slightly more complex field so we're going to add our password and our confirm password so let's head on back to our code first of all let's scroll to our form schema at the top here we want to add a password now and this is going to be of type string so we need to add z. string here now usually with passwords you're going to want to have a minimum length of at least three characters so we can use the Min function as well and we want to specify something like three in here next let's add our password confirm so let's add password confirm as well this also will be of type string and we don't need to add the Min here because we're going to do some custom validation check to make sure password and password confirm both have the same value to do that we can use the refine function so after our Zed doob here we can use the refine function now this refined function will be passed a callback function and the first argument to this callback function will contain all the data for our form so we can see here it's going to contain email address password and password confirm now from this callback function we need to return either true or false if we return true we're saying that our form validation is valid if we return false we're saying it's invalid and then we can also provide some error message and targeting as well the appropriate form field so in here we want to return if data. password is equal to data. password confirm now this will equal to true if they're both equal to each other obviously which means that our form is valid however if these aren't equal to each other then this statement will equal false and it means that our form is invalid so to display a custom error message then based on this validation logic here we can pass a second argument to the refine function and we want to pass a message here and the message is going to be something like passwords do not match then we want to pass a path now this path will be an array and we want to specify only one element in this array and we want to specify the field that this error belongs to and it should be belonging to the password confirm so we need to pass password confirm in like so from here then all we need to do is add our password and password confirm form fields to our markup so if we scroll down to our return markup we may as well just copy the form field we already have for the email address and just modify that so let's copy our email address form field and paste it underneath we're going to update the form field name to password we're going to update the form label to password the placeholder again this will be password the type will be password and we want to do exactly the same we want to copy this now and do exactly the same for the password confirm so let's update this to say password confirm we'll have the form label password confirm placeholder password confirm and the type will be password so let's save this now and take a look in the browser let's give Local Host 3000 a refresh let's hit submit and there we go we can see we're having error messages now on password and password confirm let's make sure this all works though so let's add test test.com in here let's add a dummy password in here and then let's add a password which doesn't match the actual password we entered in the first field here and there we go we can see our error message saying passwords do not match let's add the correct password and there we go that error message goes away so from here the last bit of complexity we want to add is the dropdown for what type of account we have so if we want to create a personal or a company account and then if it's a company account we want to display that optional field of company name and obviously if it's a company account the company name is actually required so it must be filled in before the form can be submit so again let's head on back to our code let's add all this in then if we scroll to the top for our form schema in our object here we want to specify account type and we can set this equal to z. enum passing in an array of all the allowed values for this form field so we're only going to allow personal and Company next we want to add a company name and we want to set this equal to z. string so it's going to be of typ string but by default we want this to be optional we don't want this to be a required field so we can use the optional function from here we want to add another custom refine function because although this company name is optional we want to check to see if account type is equal to company then company name must actually be filled in so we can add this as another refine function in here again we'll pass a callback function and the Callback function will we pass the data for our form we want to check to see if data do account type is equal to company if it is then we want to return if company or data. company name actually has a value so if data. compan name has a value if account type is equal to company this statement will return true which means our form is valid however if account type is equal to company and data. compan name doesn't have a value then this statement will equal to false which means our form is invalid then we also need to add a default return here so we'll hit this default return if data. account type is equal to personal so we don't want to do any check on company name if the account type is personal so we can just return true here however we want to add an error message as well a custom error message if no company name has been supplied for a company account type so we can add a message here and this message will be something like company name is required and the path for this error message will be if we scroll to the top here we need to specify company name so let's add company name in like so so all we need to do now is add our remaining form fields in for our account type and our company name however account type is going to be a select which means we need to install the select from Shaden UI so let's head on back to the Shaden documentation let's scroll down here to the select now we want to scroll down to the installation let's copy the CLI command here it's npx shats and UI at latest ad select so let's copy that and head on back to our terminal let's paste that in our terminal to install the select package or the select component then we can use this select component if we scroll down we want to add this actually underneath the email address so again we're just going to copy the form field here for email address and underneath email address let's paste in our new form field so this now our form field will be the account type and for the render function it's going to be slightly different here because we need to render our select form field rather than an input so instead of email address here for the form label we want to add account type now within this form control we want to remove the input and we want to render a select trigger now the select trigger is essentially just that it's just a part of the Dom which when we click on it it's going to display the select dropdown now the reason Shaden does it this way is because it means we get so much nicer looking select elements I don't know about you but the default select dropdowns just look really ugly and really gross so this is shad cen's version of a select and this is how they implement it so we have this select trigger whenever we click on this select trigger it will open up that dropdown I.E the select options so then within the select trigger we want to add a select value which we need to import from at components /ui select and one important thing to note as well is the select trigger and the select value can also be imported if we scroll to the top here they can also be imported from this package here however I've accidentally imported select trigger from the wrong package or from the wrong place we need to import select trigger from at/ component /i/ select so let's remove the incorrect import at the top here then if we scroll down to our markup again for our select value we want to add a placeholder and we'll set this equal to something like select an account type then underneath the form control this is where we want to render our select options so to do that we can use the select content from Shad CN UI and we need to import it from at/ components /ui select then we want to render the select item and again this comes from at/ component /ui select now we want to render two select items the first will have a value of personal and the label will be personal then the second will have a value of company and the label will be company like so so we want these values to match the values we have in our form schema remember we said that an account type can only either be personal or company now there's one thing I forgot to do as well for this select and that is actually to render the select component so the select component is going to wrap all of our mark up here which means we need to import the select component from at components slui select and we just want to wrap all of this particular bits of Mark up here from the form label down to the form message we need to wrap it in the select and we need to add an on value change prop set equal to field. onchange so if we save this now and before we take a look in the browser we need to make sure that we can actually access whenever we have a valid form submission we want to be able to access the form field values within the handle submit function so to do that we can grab the values that gets passed to handle submit and this is going to be of type Zed infer and type of form schema so exactly the same as what we've got at the top here so let's just copy what we've got here for our use form hook and paste this in for our type for our handle submit form values so then let's just conso log our values on a successful form submission so if we rerun then mpm run Dev in the terminal and if we head on over to Local Host 3000 again let's open up our console as well just so we can see and make sure everything is working let's first of all hit submit on our form and there we go we can see all of the appropriate error messages are displaying let's go through these one by one let's at test at test.com the email address goes away we need to select an account type this is required so let's select personal first let's add in an example password let's make sure our password confirm also works so passwords do not match let's make sure that the passwords do match and there we go we have no error messages which means we have a valid form let's hit submit and we can see our values being conso logged in our console down here so from here all we need to do is hook up our company so our company name anytime we select the company account type we need to add another field underneath the account type called company name and one thing as well I'll note is we're getting this error in the console here we scroll up let's find the actual error message so we got a component is changing an uncontrolled input to be controlled now the reason this is happening is because if we go back to our code all of our form field values aside from if we scroll down to our use form hook aside from email address are actually undefined so this is why react is actually complaining we need to set all of our form fields to an empty string so we can actually see this in the console log in the browser it says here this is likely caused by the value changing from undefined to a defined value which should not happen so to get around this we need to set the default values to an empty string so the value is defined so again if we head on back to our code let's add in the default values the account type we don't actually need to add a default value because that's going to be changed via the select however the password we need to set to an empty string the password confirm we need to set to an empty string and the company name which we're not using yet but we're actually going to implement now we want to set that to an empty string as well so then let's implement this company name first of all we need to grab the value of the account type now the only way so far we can grab a form field value is via this handle submit ideally though we want to hook in to anytime the account type changes on our form we want to hook into that change and then if the account type is equal to company then we'll conditionally render a new input called company name so to do that with the react to form we can just use the watch function so in here we can go const account type and set this equal to form. and we want to watch on account type so anytime account type changes now this account type const will update and of course our component will render so then let's use this account type then we want to check to see if it's equal to company let's scroll down then first of all let's copy our email address form field again and underneath account type let's paste in that new field however we want to conditionally render this so we only want to render this if account type is equal to company and only then will we render the company name form field so let's add our closing curly brace down here now for this form field we want this to be company name we want the form label to be company name the placeholder again we want this to be equal to company name the type we'll remove this because it's going to be of type text so if we save this now then and take a look here in the browser let's give Local Host 3,000 a refresh let's add our dummy data in for our form fields we know the password's working so that's fine we don't need to check that again but now let's hit submit we can see an account type is required let's select personal let's hit submit now there we go we can see our console log for our form values so this means this was a successful form submission but now if we select company let's see what happens if we hit submit we get this error message so company name is required so let's add in a company name let's hit submit and there we go we have another valid submission
Info
Channel: WebDevEducation
Views: 16,720
Rating: undefined out of 5
Keywords: react hook form, next js form validation, shadcn ui, zod tutorial
Id: oGq9o2BxlaI
Channel Id: undefined
Length: 27min 59sec (1679 seconds)
Published: Fri Nov 24 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.