PromptBase
Upgrade
Close icon
General
Home
Marketplace
Create
Hire
Login
Chat
Sell
Explore

Prompt Details

Model
(claude-4-6-sonnet)
Token size
550
Example input
[USER_SPEC]: Registration form in English (professional tone). Fields: first name, last name, email, password, confirm password, date of birth. Validation: email must be a business address (no gmail/yahoo/hotmail), password min 8 chars with uppercase + number + special char, passwords must match, age 18+. No masking needed
Example output
import { useState } from "react"; import { useForm, Controller } from "react-hook-form"; import { zodResolver } from "@hookform/resolvers/zod"; import { z } from "zod"; // ─── Zod Schema ─────────────────────────────────────────────────────────────── const BLOCKED_DOMAINS = ["gmail.com", "yahoo.com", "hotmail.com", "outlook.com", "live.com", "icloud.com", "aol.com", "mail.com", "protonmail.com", "yandex.com"]; const registrationSchema = z .object({ firstName: z .string() .min(1, "First name is required.") .min(2, "First name must be at least 2 characters.") .max(50, "First name must not exceed 50 characters."), lastName: z .string() .min(1, "Last name is required.") .min(2, "Last name must be at least 2 characters.") .max(50, "Last name must not exceed 50 characters."), email: z .string() .min(1, "Email address is required.") .email("Please enter a valid email address.") .refine((val) => { const domain = val.split("@")[1]?.toLowerCase(); if (!domain) return false; return !BLOCKED_DOMAINS.includes(domain); }, "Please use a business email address. Personal email providers (Gmail, Yahoo, Hotmail, etc.) are not accepted."), password: z .string() .min(1, "Password is required.") .min(8, "Password must be at least 8 characters.") .refine((val) => /[A-Z]/.test(val), "Password must contain at least one uppercase letter.") .refine((val) => /[0-9]/.test(val), "Password must contain at least one number.") .refine((val) => /[^A-Za-z0-9]/.test(val), "Password must contain at least one special character."), confirmPassword: z.string().min(1, "Please confirm your password."), dateOfBirth: z .string() .min(1, "Date of birth is required.") .refine((val) => { const date = new Date(val); return !isNaN(date.getTime()); }, "Please enter a valid date.") .refine((val) => { const dob = new Date(val); const today = new Date(); const age = today.getFullYear() - dob.getFullYear(); const m = today.getMonth() - dob.getMonth(); const adjustedAge = m < 0 || (m === 0 && today.getDate() < dob.getDate()) ? age - 1 : age; return adjustedAge >= 18; }, "You must be at least 18 years old to register."), }) .refine((data) => data.password === data.confirmPassword, { path: ["confirmPassword"], message: "Passwords do not match.", }); // ─── Inferred Types ─────────────────────────────────────────────────────────── type RegistrationFormData = z.infer<typeof registrationSchema>; // ─── Helper Functions ───────────────────────────────────────────────────────── function getMaxDateOfBirth(): string { const today = new Date(); today.setFullYear(today.getFullYear() - 18); return today.toISOString().split("T")[0]; } function getMinDateOfBirth(): string { const today = new Date(); today.setFullYear(today.getFullYear() - 120); return today.toISOString().split("T")[0]; } function getPasswordStrength(password: string): { level: number; label: string; color: string } { if (!password) return { level: 0, label: "", color: "" }; let score = 0; if (password.length >= 8) score++; if (password.length >= 12) score++; if (/[A-Z]/.test(password)) score++; if (/[0-9]/.test(password)) score++; if (/[^A-Za-z0-9]/.test(password)) score++; if (score <= 2) return { level: 1, label: "Weak", color: "bg-red-500" }; if (score <= 3) return { level: 2, label: "Fair", color: "bg-amber-500" }; if (score <= 4) return { level: 3, label: "Good", color: "bg-blue-500" }; return { level: 4, label: "Strong", color: "bg-emerald-500" }; } // ─── Component ──────────────────────────────────────────────────────────────── export default function RegistrationForm() { const [submitted, setSubmitted] = useState(false); const [submittedData, setSubmittedData] = useState<RegistrationFormData | null>(null); const { register, handleSubmit, control, watch, formState: { errors, isSubmitting }, } = useForm<RegistrationFormData>({ resolver: zodResolver(registrationSchema), mode: "onBlur", }); const passwordValue = watch("password", ""); const strength = getPasswordStrength(passwordValue); const onSubmit = (data: RegistrationFormData) => { console.log("Registration data:", data); setSubmittedData(data); setSubmitted(true); }; if (submitted && submittedData) { return ( <div className="min-h-screen bg-slate-950 flex items-center justify-center p-6"> <div className="w-full max-w-md"> <div className="bg-slate-900 border border-slate-700/50 rounded-2xl p-8 shadow-2xl shadow-black/40 text-center"> <div className="w-16 h-16 bg-emerald-500/10 border border-emerald-500/30 rounded-full flex items-center justify-center mx-auto mb-6"> <svg className="w-8 h-8 text-emerald-400" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}> <path strokeLinecap="round" strokeLinejoin="round" d="M5 13l4 4L19 7" /> </svg> </div> <h2 className="text-2xl font-semibold text-white mb-2 tracking-tight">Registration Successful</h2> <p className="text-slate-400 text-sm leading-relaxed"> Welcome, <span className="text-white font-medium">{submittedData.firstName} {submittedData.lastName}</span>. Your account has been created successfully. A confirmation email will be sent to <span className="text-white font-medium">{submittedData.email}</span>. </p> <button onClick={() => { setSubmitted(false); setSubmittedData(null); }} className="mt-6 text-sm text-slate-500 hover:text-slate-300 transition-colors duration-200 underline underline-offset-4" > Register another account </button> </div> </div> </div> ); } return ( <div className="min-h-screen bg-slate-950 flex items-center justify-center p-6"> {/* Background grid */} <div className="fixed inset-0 bg-[linear-gradient(to_right,#1e293b_1px,transparent_1px),linear-gradient(to_bottom,#1e293b_1px,transparent_1px)] bg-[size:64px_64px] opacity-40 pointer-events-none" /> <div className="fixed inset-0 bg-[radial-gradient(ellipse_80%_50%_at_50%_-20%,rgba(99,102,241,0.15),transparent)] pointer-events-none" /> <div className="relative w-full max-w-lg"> {/* Header */} <div className="mb-8 text-center"> <div className="inline-flex items-center gap-2 bg-indigo-500/10 border border-indigo-500/20 rounded-full px-4 py-1.5 mb-5"> <div className="w-1.5 h-1.5 rounded-full bg-indigo-400 animate-pulse" /> <span className="text-xs text-indigo-300 font-medium tracking-wide uppercase">New Account</span> </div> <h1 className="text-3xl font-bold text-white tracking-tight mb-2">Create your account</h1> <p className="text-slate-400 text-sm">Complete the form below to get started with our platform.</p> </div> {/* Form card */} <div className="bg-slate-900/80 backdrop-blur-sm border border-slate-700/50 rounded-2xl shadow-2xl shadow-black/40 p-8"> <form onSubmit={handleSubmit(onSubmit)} noValidate className="space-y-5"> {/* Name row */} <div className="grid grid-cols-2 gap-4"> {/* First Name */} <div className="flex flex-col gap-1.5"> <label htmlFor="firstName" className="text-xs font-semibold text-slate-300 uppercase tracking-wider"> First Name </label> <input id="firstName" type="text" placeholder="Jane" autoComplete="given-name" aria-invalid={!!errors.firstName} aria-describedby={errors.firstName ? "firstName-error" : undefined} {...register("firstName")} className={`w-full bg-slate-800/60 border rounded-xl px-4 py-3 text-white placeholder-slate-500 text-sm transition-all duration-200 outline-none focus:ring-2 focus:ring-indigo-500/50 focus:border-indigo-500/50 hover:border-slate-600 ${ errors.firstName ? "border-red-500/60 focus:ring-red-500/30" : "border-slate-700/60" }`} /> {errors.firstName && ( <p id="firstName-error" role="alert" className="text-xs text-red-400 flex items-start gap-1 mt-0.5"> <span className="mt-0.5 shrink-0">⚠</span> {errors.firstName.message} </p> )} </div> {/* Last Name */} <div className="flex flex-col gap-1.5"> <label htmlFor="lastName" className="text-xs font-semibold text-slate-300 uppercase tracking-wider"> Last Name </label> <input id="lastName" type="text" placeholder="Doe" autoComplete="family-name" aria-invalid={!!errors.lastName} aria-describedby={errors.lastName ? "lastName-error" : undefined} {...register("lastName")} className={`w-full bg-slate-800/60 border rounded-xl px-4 py-3 text-white placeholder-slate-500 text-sm transition-all duration-200 outline-none focus:ring-2 focus:ring-indigo-500/50 focus:border-indigo-500/50 hover:border-slate-600 ${ errors.lastName ? "border-red-500/60 focus:ring-red-500/30" : "border-slate-700/60" }`} /> {errors.lastName && ( <p id="lastName-error" role="alert" className="text-xs text-red-400 flex items-start gap-1 mt-0.5"> <span className="mt-0.5 shrink-0">⚠</span> {errors.lastName.message} </p> )} </div> </div> {/* Email */} <div className="flex flex-col gap-1.5"> <label htmlFor="email" className="text-xs font-semibold text-slate-300 uppercase tracking-wider"> Business Email Address </label> <input id="email" type="email" placeholder="jane.doe@company.com" autoComplete="email" aria-invalid={!!errors.email} aria-describedby={errors.email ? "email-error" : "email-hint"} {...register("email")} className={`w-full bg-slate-800/60 border rounded-xl px-4 py-3 text-white placeholder-slate-500 text-sm transition-all duration-200 outline-none focus:ring-2 focus:ring-indigo-500/50 focus:border-indigo-500/50 hover:border-slate-600 ${ errors.email ? "border-red-500/60 focus:ring-red-500/30" : "border-slate-700/60" }`} /> {errors.email ? ( <p id="email-error" role="alert" className="text-xs text-red-400 flex items-start gap-1 mt-0.5"> <span className="mt-0.5 shrink-0">⚠</span> {errors.email.message} </p> ) : ( <p id="email-hint" className="text-xs text-slate-500"> Personal email providers are not accepted. </p> )} </div> {/* Password */} <div className="flex flex-col gap-1.5"> <label htmlFor="password" className="text-xs font-semibold text-slate-300 uppercase tracking-wider"> Password </label> <input id="password" type="password" placeholder="Create a strong password" autoComplete="new-password" aria-invalid={!!errors.password} aria-describedby={errors.password ? "password-error" : "password-hint"} {...register("password")} className={`w-full bg-slate-800/60 border rounded-xl px-4 py-3 text-white placeholder-slate-500 text-sm transition-all duration-200 outline-none focus:ring-2 focus:ring-indigo-500/50 focus:border-indigo-500/50 hover:border-slate-600 ${ errors.password ? "border-red-500/60 focus:ring-red-500/30" : "border-slate-700/60" }`} /> {/* Strength indicator */} {passwordValue && ( <div className="mt-1 space-y-1.5"> <div className="flex gap-1"> {[1, 2, 3, 4].map((i) => ( <div key={i} className={`h-1 flex-1 rounded-full transition-all duration-300 ${ i <= strength.level ? strength.color : "bg-slate-700" }`} /> ))} </div> {strength.label && ( <p className="text-xs text-slate-400"> Password strength: <span className="font-medium text-slate-300">{strength.label}</span> </p> )} </div> )} {errors.password ? ( <p id="password-error" role="alert" className="text-xs text-red-400 flex items-start gap-1 mt-0.5"> <span className="mt-0.5 shrink-0">⚠</span> {errors.password.message} </p> ) : ( <p id="password-hint" className="text-xs text-slate-500"> Minimum 8 characters — must include uppercase, number, and special character. </p> )} </div> {/* Confirm Password */} <div className="flex flex-col gap-1.5"> <label htmlFor="confirmPassword" className="text-xs font-semibold text-slate-300 uppercase tracking-wider"> Confirm Password </label> <input id="confirmPassword" type="password" placeholder="Re-enter your password" autoComplete="new-password" aria-invalid={!!errors.confirmPassword} aria-describedby={errors.confirmPassword ? "confirmPassword-error" : undefined} {...register("confirmPassword")} className={`w-full bg-slate-800/60 border rounded-xl px-4 py-3 text-white placeholder-slate-500 text-sm transition-all duration-200 outline-none focus:ring-2 focus:ring-indigo-500/50 focus:border-indigo-500/50 hover:border-slate-600 ${ errors.confirmPassword ? "border-red-500/60 focus:ring-red-500/30" : "border-slate-700/60" }`} /> {errors.confirmPassword && ( <p id="confirmPassword-error" role="alert" className="text-xs text-red-400 flex items-start gap-1 mt-0.5"> <span className="mt-0.5 shrink-0">⚠</span> {errors.confirmPassword.message} </p> )} </div> {/* Date of Birth */} <div className="flex flex-col gap-1.5"> <label htmlFor="dateOfBirth" className="text-xs font-semibold text-slate-300 uppercase tracking-wider"> Date of Birth </label> <Controller name="dateOfBirth" control={control} render={({ field }) => ( <input id="dateOfBirth" type="date" max={getMaxDateOfBirth()} min={getMinDateOfBirth()} autoComplete="bday" aria-invalid={!!errors.dateOfBirth} aria-describedby={errors.dateOfBirth ? "dateOfBirth-error" : "dateOfBirth-hint"} {...field} className={`w-full bg-slate-800/60 border rounded-xl px-4 py-3 text-white placeholder-slate-500 text-sm transition-all duration-200 outline-none focus:ring-2 focus:ring-indigo-500/50 focus:border-indigo-500/50 hover:border-slate-600 [color-scheme:dark] ${ errors.dateOfBirth ? "border-red-500/60 focus:ring-red-500/30" : "border-slate-700/60" }`} /> )} /> {errors.dateOfBirth ? ( <p id="dateOfBirth-error" role="alert" className="text-xs text-red-400 flex items-start gap-1 mt-0.5"> <span className="mt-0.5 shrink-0">⚠</span> {errors.dateOfBirth.message} </p> ) : ( <p id="dateOfBirth-hint" className="text-xs text-slate-500"> You must be at least 18 years old to register. </p> )} </div> {/* Divider */} <div className="border-t border-slate-700/50 pt-2" /> {/* Submit */} <button type="submit" disabled={isSubmitting} className="w-full bg-indigo-600 hover:bg-indigo-500 disabled:bg-indigo-800 disabled:cursor-not-allowed text-white font-semibold text-sm rounded-xl px-6 py-3.5 transition-all duration-200 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 focus:ring-offset-slate-900 shadow-lg shadow-indigo-500/20 hover:shadow-indigo-500/30 active:scale-[0.99]" > {isSubmitting ? ( <span className="flex items-center justify-center gap-2"> <svg className="w-4 h-4 animate-spin" viewBox="0 0 24 24" fill="none"> <circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4" /> <path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z" /> </svg> Processing… </span> ) : ( "Create Account" )} </button> <p className="text-center text-xs text-slate-500 leading-relaxed"> By creating an account, you agree to our{" "} <span className="text-slate-400 hover:text-white transition-colors cursor-pointer">Terms of Service</span>{" "} and{" "} <span className="text-slate-400 hover:text-white transition-colors cursor-pointer">Privacy Policy</span>. </p> </form> </div> </div> </div> ); }
🌀 Claude

Expert React Form Generator

Add to Cart
Instant accessInstant access
Usage rightsCommercial use
Money-back guaranteeMoney‑back
By purchasing this prompt, you agree to our terms of service
CLAUDE-4-6-SONNET
Tested icon
Guide icon
4 examples icon
Free credits icon
Generate polished, production-ready React forms instantly. One prompt → full TypeScript component with Zod validation, React Hook Form, input masking, accessibility (WCAG AA), and beautiful Tailwind UI. Supports any language, complex rules (Luhn, PESEL, NIP, business email), and multi-field logic. No extra libraries needed. Tested on snadbox. You can quickly see the form in the sandbox I prepared, link in the manual
...more
Added over 1 month ago
Report
Browse Marketplace