Introduction
Prerequisites
Setting up project
npx create-next-app@latest app-name --typescript --tailwind --eslint
Run the shadcn-ui init command to set up your project:
npx shadcn-ui@latest init
You will be asked a few questions to configure components.json:
Would you like to use TypeScript (recommended)? no / yes
Which style would you like to use? › Default
Which color would you like to use as base color? › Slate
Where is your global CSS file? › › app/globals.css
Do you want to use CSS variables for colors? › no / yes
Where is your tailwind.config.js located? › tailwind.config.js
Configure the import alias for components: › @/components
Configure the import alias for utils: › @/lib/utils
Are you using React Server Components? › no / yes
Designing the Sign-Up Form
├── app│ ├── (auth)├── (routes)├── signup├── [[...signup]]├── page.tsx & layout.tsx
In-app folder create a folder named (auth) then in that folder create another folder named (routes) then in that folder create another folder signup then again create a new folder in that folder named [[...signup]] in that folder create a file named page.tsx and layout.txs
In that page.tsx file paste this code:
First, install these npm packages:
npm i zod react-hook-form react-icons
"use client"
import React from 'react'
import * as z from "zod"
import { Button } from "@/components/ui/button"
import { zodResolver } from "@hookform/resolvers/zod"
import { useForm } from 'react-hook-form'
import {
Form,
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
} from "@/components/ui/form"
import { Input } from "@/components/ui/input"
import { FaFacebook, FaGithub, FaGoogle } from "react-icons/fa6";
import Link from 'next/link'
const signUpSchema = z.object({
name: z.string().min(2, "Name Should have atleast 2 characters.").max(50, "Name should not exceed 50 characters.").refine((value) => /^[a-zA-Z]+[-'s]?[a-zA-Z ]+$/.test(value), 'Name should contain only alphabets.'),
email: z.string().email("Email must be valid."),
password: z.string().min(6, "Password Should have atleast 6 characters."),
confirmPassword: z.string().min(6, "Password Should have atleast 6 characters.")
}).refine((data) => data.password === data.confirmPassword, {
message: "Passwords does not match.",
path: ["confirmPassword"],
});
const SignUpPage = () => {
const form = useForm<z.infer<typeof signUpSchema>>({
resolver: zodResolver(signUpSchema),
defaultValues: {
name: "",
email: "",
password: "",
confirmPassword: "",
},
})
function onSubmit(values: z.infer<typeof signUpSchema>) {
console.log(values)
}
return (
<>
<div className="signUpWrapper">
<div className="formWrapper">
<div className="left">
<h3 className="title">Welcome Back!</h3>
<p>To keep connected with us please login with your personal info</p>
<Link href={"/signin"}>
<Button className='border-zinc-500 text-zinc-300 hover:border-zinc-200 hover:text-zinc-100 transition-colors border rounded-full px-8'>Sign In</Button>
</Link>
</div>
<div className="right">
<h3 className='text-center text-2xl font-semibold'>Register Here</h3>
<div className="socialSignUpOptions">
<Button variant={"outline"} className='socialFormBtn'><FaGoogle className="h-5 w-5"/></Button>
<Button variant={"outline"} className='socialFormBtn'><FaFacebook className="h-5 w-5"/></Button>
<Button variant={"outline"} className='socialFormBtn'><FaGithub className="h-5 w-5"/></Button>
</div>
<p className='text-center'>or use this option</p>
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)}>
<FormField
control={form.control}
name="name"
render={({ field }) => (
<FormItem className='space-y-0 mb-2'>
<FormLabel>Name</FormLabel>
<FormControl>
<Input placeholder="Jhon Deo" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="email"
render={({ field }) => (
<FormItem className='space-y-0 mb-2'>
<FormLabel>Email</FormLabel>
<FormControl>
<Input placeholder="admin@example.com" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="password"
render={({ field }) => (
<FormItem className='space-y-0 mb-2'>
<FormLabel>Password</FormLabel>
<FormControl>
<Input placeholder="********" type='password' {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="confirmPassword"
render={({ field }) => (
<FormItem className='space-y-0 mb-2'>
<FormLabel>Confirm Password</FormLabel>
<FormControl>
<Input placeholder="********" type='password' {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<Button type="submit" className='w-full'>Submit</Button>
</form>
</Form>
</div>
</div>
</div>
</>
)
}
export default SignUpPage
.signUpWrapper,
.signInWrapper{
@apply h-screen w-full flex justify-center items-center
}
.formWrapper{
@apply flex items-center border bg-primary shadow-md rounded-lg overflow-hidden justify-center w-[20rem] mx-6 md:w-auto my-4
}
.signUpWrapper .left,
.signInWrapper .left{
@apply bg-primary text-muted hidden md:flex justify-center items-center flex-col
}
.signUpWrapper .left .title,
.signInWrapper .left .title {
@apply text-2xl font-semibold
}
.signUpWrapper .left p,
.signInWrapper .left p {
@apply text-sm max-w-[90%] text-center mb-3
}
.signInWrapper .right,
.signUpWrapper .right{
@apply px-4 py-4 my-4 mx-4 md:w-1/2 w-[20rem] bg-white rounded-lg
}
.socialFormBtn{
@apply rounded-full h-[2.5rem] w-[2.5rem] p-0 mx-2 border-zinc-400
}
.socialSignUpOptions{
@apply my-3 flex justify-center items-center
}