Auth Forms

Complete authentication forms including login, registration, and password reset. Features social login buttons, password visibility toggle, and smooth transitions.

Login FormRegistrationSocial LoginPassword ResetPassword Toggle

Installation

Terminal
ReactTailwind
TSX
npx @uiblox/cli add auth-forms

Preview

Welcome back

Sign in to continue

or

No account?

Source Code

auth-forms.tsx
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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
"use client"; import { useState } from "react"; import { cn } from "@/lib/utils"; type AuthMode = "login" | "register" | "forgot-password"; export function AuthForms() { const [mode, setMode] = useState<AuthMode>("login"); const [showPassword, setShowPassword] = useState(false); return ( <div className="min-h-screen flex items-center justify-center bg-slate-100 dark:bg-slate-950 p-4"> <div className="w-full max-w-md"> {/* Logo */} <div className="text-center mb-8"> <div className="inline-flex items-center justify-center w-12 h-12 bg-purple-600 rounded-xl mb-4"> <LogoIcon /> </div> <h1 className="text-2xl font-bold text-slate-900 dark:text-white"> {mode === "login" && "Welcome back"} {mode === "register" && "Create an account"} {mode === "forgot-password" && "Reset password"} </h1> <p className="text-slate-500 mt-2"> {mode === "login" && "Sign in to your account to continue"} {mode === "register" && "Start your 14-day free trial"} {mode === "forgot-password" && "We'll send you a reset link"} </p> </div> {/* Form Card */} <div className="bg-white dark:bg-slate-900 rounded-2xl border border-slate-200 dark:border-slate-800 p-8 shadow-xl shadow-slate-200/50 dark:shadow-slate-950/50"> {/* Social Login */} {mode !== "forgot-password" && ( <> <div className="grid grid-cols-2 gap-3 mb-6"> <button className="flex items-center justify-center gap-2 px-4 py-2.5 border border-slate-200 dark:border-slate-700 rounded-xl hover:bg-slate-50 dark:hover:bg-slate-800 transition-colors"> <GoogleIcon /> <span className="text-sm font-medium text-slate-700 dark:text-slate-300">Google</span> </button> <button className="flex items-center justify-center gap-2 px-4 py-2.5 border border-slate-200 dark:border-slate-700 rounded-xl hover:bg-slate-50 dark:hover:bg-slate-800 transition-colors"> <GitHubIcon /> <span className="text-sm font-medium text-slate-700 dark:text-slate-300">GitHub</span> </button> </div> <div className="relative mb-6"> <div className="absolute inset-0 flex items-center"> <div className="w-full border-t border-slate-200 dark:border-slate-800" /> </div> <div className="relative flex justify-center text-sm"> <span className="px-4 bg-white dark:bg-slate-900 text-slate-500">or continue with</span> </div> </div> </> )} {/* Form */} <form className="space-y-4"> {mode === "register" && ( <div> <label className="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-1.5">Full Name</label> <input type="text" placeholder="John Doe" className="w-full px-4 py-2.5 border border-slate-200 dark:border-slate-700 rounded-xl bg-transparent focus:outline-none focus:ring-2 focus:ring-purple-500 text-slate-900 dark:text-white placeholder-slate-400" /> </div> )} <div> <label className="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-1.5">Email</label> <input type="email" placeholder="you@example.com" className="w-full px-4 py-2.5 border border-slate-200 dark:border-slate-700 rounded-xl bg-transparent focus:outline-none focus:ring-2 focus:ring-purple-500 text-slate-900 dark:text-white placeholder-slate-400" /> </div> {mode !== "forgot-password" && ( <div> <div className="flex items-center justify-between mb-1.5"> <label className="block text-sm font-medium text-slate-700 dark:text-slate-300">Password</label> {mode === "login" && ( <button type="button" onClick={() => setMode("forgot-password")} className="text-sm text-purple-600 hover:text-purple-700"> Forgot password? </button> )} </div> <div className="relative"> <input type={showPassword ? "text" : "password"} placeholder="••••••••" className="w-full px-4 py-2.5 border border-slate-200 dark:border-slate-700 rounded-xl bg-transparent focus:outline-none focus:ring-2 focus:ring-purple-500 text-slate-900 dark:text-white placeholder-slate-400 pr-10" /> <button type="button" onClick={() => setShowPassword(!showPassword)} className="absolute right-3 top-1/2 -translate-y-1/2 text-slate-400 hover:text-slate-600" > {showPassword ? <EyeOffIcon /> : <EyeIcon />} </button> </div> </div> )} {mode === "register" && ( <div> <label className="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-1.5">Confirm Password</label> <input type="password" placeholder="••••••••" className="w-full px-4 py-2.5 border border-slate-200 dark:border-slate-700 rounded-xl bg-transparent focus:outline-none focus:ring-2 focus:ring-purple-500 text-slate-900 dark:text-white placeholder-slate-400" /> </div> )} {mode === "register" && ( <label className="flex items-start gap-2"> <input type="checkbox" className="mt-1 rounded border-slate-300 text-purple-600 focus:ring-purple-500" /> <span className="text-sm text-slate-600 dark:text-slate-400"> I agree to the <a href="#" className="text-purple-600 hover:underline">Terms of Service</a> and <a href="#" className="text-purple-600 hover:underline">Privacy Policy</a> </span> </label> )} <button type="submit" className="w-full py-3 bg-purple-600 hover:bg-purple-700 text-white font-semibold rounded-xl transition-colors" > {mode === "login" && "Sign in"} {mode === "register" && "Create account"} {mode === "forgot-password" && "Send reset link"} </button> </form> {/* Mode Switch */} <p className="text-center mt-6 text-sm text-slate-600 dark:text-slate-400"> {mode === "login" && ( <>Don't have an account? <button onClick={() => setMode("register")} className="text-purple-600 hover:underline font-medium">Sign up</button></> )} {mode === "register" && ( <>Already have an account? <button onClick={() => setMode("login")} className="text-purple-600 hover:underline font-medium">Sign in</button></> )} {mode === "forgot-password" && ( <>Remember your password? <button onClick={() => setMode("login")} className="text-purple-600 hover:underline font-medium">Sign in</button></> )} </p> </div> {/* Footer */} <p className="text-center mt-8 text-xs text-slate-500"> Secured by enterprise-grade encryption </p> </div> </div> ); } function LogoIcon() { return <svg className="w-6 h-6 text-white" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M13 10V3L4 14h7v7l9-11h-7z" /></svg>; } function GoogleIcon() { return <svg className="w-5 h-5" viewBox="0 0 24 24"><path fill="#4285F4" d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z"/><path fill="#34A853" d="M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z"/><path fill="#FBBC05" d="M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z"/><path fill="#EA4335" d="M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z"/></svg>; } function GitHubIcon() { return <svg className="w-5 h-5 text-slate-700 dark:text-slate-300" fill="currentColor" viewBox="0 0 24 24"><path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"/></svg>; } function EyeIcon() { return <svg className="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" /><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z" /></svg>; } function EyeOffIcon() { return <svg className="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M13.875 18.825A10.05 10.05 0 0112 19c-4.478 0-8.268-2.943-9.543-7a9.97 9.97 0 011.563-3.029m5.858.908a3 3 0 114.243 4.243M9.878 9.878l4.242 4.242M9.88 9.88l-3.29-3.29m7.532 7.532l3.29 3.29M3 3l3.59 3.59m0 0A9.953 9.953 0 0112 5c4.478 0 8.268 2.943 9.543 7a10.025 10.025 0 01-4.132 5.411m0 0L21 21" /></svg>; }