AuthForm

A flexible authentication form component supporting both sign in and sign up flows.

Usage

YourBanK logo

YourBanK

Sign In

Please enter your details

1
2
3
4
5
6
7
8
9
import AuthForm from "@/components/AuthForm"

export default function LoginPage() {
  return (
    <div className="max-w-sm mx-auto">
      <AuthForm type="login" />
    </div>
  )
}

Props

variant

The form variant to display: "login" or "register".

Type: "login" | "register" (optional, defaults to "login")

onSubmit

Callback function called when the form is submitted.

Type: (data: AuthFormData) => Promise<void> (optional)

className

Additional CSS classes to apply to the form container.

Type: string (optional)

Implementation

The complete implementation of the AuthForm component:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
"use client"

import * as React from "react"
import { useForm } from "react-hook-form"
import { zodResolver } from "@hookform/resolvers/zod"
import * as z from "zod"
import { Button } from "@/components/ui/button"
import {
  Form,
  FormControl,
  FormField,
  FormItem,
  FormLabel,
  FormMessage,
} from "@/components/ui/form"
import { Input } from "@/components/ui/input"
import { cn } from "@/lib/utils"

const authFormSchema = z.object({
  email: z.string().email("Please enter a valid email address"),
  password: z
    .string()
    .min(8, "Password must be at least 8 characters")
    .max(100, "Password must be less than 100 characters"),
})

export type AuthFormData = z.infer<typeof authFormSchema>

interface AuthFormProps {
  variant?: "login" | "register"
  onSubmit?: (data: AuthFormData) => Promise<void>
  className?: string
}

export function AuthForm({
  variant = "login",
  onSubmit,
  className,
}: AuthFormProps) {
  const [isLoading, setIsLoading] = React.useState(false)

  const form = useForm<AuthFormData>({
    resolver: zodResolver(authFormSchema),
    defaultValues: {
      email: "",
      password: "",
    },
  })

  async function handleSubmit(data: AuthFormData) {
    setIsLoading(true)
    try {
      await onSubmit?.(data)
    } catch (error) {
      console.error(error)
    } finally {
      setIsLoading(false)
    }
  }

  return (
    <Form {...form}>
      <form
        onSubmit={form.handleSubmit(handleSubmit)}
        className={cn("space-y-6", className)}
      >
        <FormField
          control={form.control}
          name="email"
          render={({ field }) => (
            <FormItem>
              <FormLabel>Email</FormLabel>
              <FormControl>
                <Input
                  placeholder="m@example.com"
                  type="email"
                  disabled={isLoading}
                  {...field}
                />
              </FormControl>
              <FormMessage />
            </FormItem>
          )}
        />
        <FormField
          control={form.control}
          name="password"
          render={({ field }) => (
            <FormItem>
              <FormLabel>Password</FormLabel>
              <FormControl>
                <Input
                  placeholder="••••••••"
                  type="password"
                  disabled={isLoading}
                  {...field}
                />
              </FormControl>
              <FormMessage />
            </FormItem>
          )}
        />
        <Button
          type="submit"
          className="w-full bg-[#39A36A] hover:bg-[#2E8754]"
          disabled={isLoading}
        >
          {variant === "login" ? "Sign In" : "Sign Up"}
        </Button>
      </form>
    </Form>
  )
}