Reset Password
Customizable password reset form built with Tailwind CSS

- Tailwind CSS v4
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Reset Password Form</title>
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/alpinejs/3.13.3/cdn.min.js" defer></script>
<style>
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap');
body { font-family: 'Inter', sans-serif; }
</style>
</head>
<body class="min-h-screen bg-gradient-to-br from-blue-50 via-white to-purple-50 flex items-center justify-center p-4">
<div class="w-full max-w-md">
<!-- Form Container -->
<div class="bg-white/80 backdrop-blur-sm rounded-2xl shadow-xl border border-white/20 p-8 transform transition-all duration-300 hover:shadow-2xl">
<!-- Header -->
<div class="text-center mb-8">
<div class="inline-flex items-center justify-center w-16 h-16 bg-gradient-to-br from-blue-500 to-purple-600 rounded-full mb-4 shadow-lg">
<svg class="w-8 h-8 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 7a2 2 0 012 2m0 0a2 2 0 012 2m-2-2a2 2 0 00-2 2m2-2V5a2 2 0 00-2-2H9a2 2 0 00-2 2v2m0 0a2 2 0 102 2m-2-2a2 2 0 012 2m0 0V9a2 2 0 012-2m-2 2H7a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2V9a2 2 0 00-2-2m-2 2v10a2 2 0 01-2 2H9a2 2 0 01-2-2V9a2 2 0 012-2h2"></path>
</svg>
</div>
<h2 class="text-3xl font-bold text-gray-900 mb-2">Reset Password</h2>
<p class="text-gray-600">Enter your email address and we'll send you a link to reset your password.</p>
</div>
<!-- Form -->
<form
x-data="{
email: '',
isLoading: false,
isSubmitted: false,
errors: {},
validateEmail() {
const emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
this.errors = {};
if (!this.email) {
this.errors.email = 'Email is required';
return false;
}
if (!emailPattern.test(this.email)) {
this.errors.email = 'Please enter a valid email address';
return false;
}
return true;
},
async submitForm() {
if (!this.validateEmail()) return;
this.isLoading = true;
// Simulate API call
await new Promise(resolve => setTimeout(resolve, 2000));
this.isLoading = false;
this.isSubmitted = true;
}
}"
@submit.prevent="submitForm()"
class="space-y-6"
>
<!-- Success Message -->
<div
x-show="isSubmitted"
x-transition:enter="transition ease-out duration-300"
x-transition:enter-start="opacity-0 transform scale-95"
x-transition:enter-end="opacity-100 transform scale-100"
class="bg-green-50 border border-green-200 rounded-xl p-4 text-center"
>
<div class="flex items-center justify-center w-12 h-12 bg-green-100 rounded-full mx-auto mb-3">
<svg class="w-6 h-6 text-green-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path>
</svg>
</div>
<h3 class="text-lg font-semibold text-green-800 mb-2">Check your email!</h3>
<p class="text-green-700 text-sm">We've sent a password reset link to <span class="font-medium" x-text="email"></span></p>
</div>
<!-- Form Fields -->
<div x-show="!isSubmitted" x-transition:leave="transition ease-in duration-200" x-transition:leave-start="opacity-100" x-transition:leave-end="opacity-0">
<!-- Email Input -->
<div class="space-y-2">
<label for="email" class="block text-sm font-medium text-gray-700">Email Address</label>
<div class="relative">
<div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
<svg class="h-5 w-5 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 12a4 4 0 10-8 0 4 4 0 008 0zm0 0v1.5a2.5 2.5 0 005 0V12a9 9 0 10-9 9m4.5-1.206a8.959 8.959 0 01-4.5 1.207"></path>
</svg>
</div>
<input
id="email"
type="email"
x-model="email"
@blur="validateEmail()"
@input="errors.email = ''"
:class="errors.email ? 'border-red-300 focus:border-red-500 focus:ring-red-500' : 'border-gray-300 focus:border-blue-500 focus:ring-blue-500'"
class="block w-full pl-10 pr-3 py-3 border rounded-xl focus:outline-none focus:ring-2 focus:ring-opacity-50 transition-all duration-200 bg-gray-50 focus:bg-white"
placeholder="Enter your email address"
autocomplete="email"
>
</div>
<p x-show="errors.email" x-text="errors.email" class="text-red-600 text-sm mt-1 transition-all duration-200"></p>
</div>
<!-- Submit Button -->
<button
type="submit"
:disabled="isLoading"
:class="isLoading ? 'bg-gray-400 cursor-not-allowed' : 'bg-gradient-to-r from-blue-500 to-purple-600 hover:from-blue-600 hover:to-purple-700 transform hover:scale-[1.02] active:scale-[0.98]'"
class="w-full flex items-center justify-center px-4 py-3 rounded-xl text-white font-semibold transition-all duration-200 shadow-lg hover:shadow-xl disabled:shadow-none"
>
<span x-show="!isLoading">Send Reset Link</span>
<span x-show="isLoading" class="flex items-center">
<svg class="animate-spin -ml-1 mr-3 h-5 w-5 text-white" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
</svg>
Sending...
</span>
</button>
</div>
<!-- Back to Login -->
<div class="text-center pt-4 border-t border-gray-100">
<p class="text-sm text-gray-600">
Remember your password?
<a href="#" class="font-medium text-blue-600 hover:text-blue-500 transition-colors duration-200">
Back to Login
</a>
</p>
</div>
</form>
<!-- Try Again Button (shown after success) -->
<div x-show="isSubmitted" x-transition:enter="transition ease-out duration-300 delay-300" x-transition:enter-start="opacity-0" x-transition:enter-end="opacity-100" class="mt-6">
<button
@click="isSubmitted = false; email = ''; errors = {}"
class="w-full px-4 py-3 bg-gray-100 hover:bg-gray-200 text-gray-700 font-medium rounded-xl transition-all duration-200 hover:scale-[1.02] active:scale-[0.98]"
>
Send to Different Email
</button>
</div>
</div>
<!-- Additional Info -->
<div class="mt-6 text-center">
<p class="text-sm text-gray-500">
Didn't receive the email? Check your spam folder or
<button @click="submitForm()" class="text-blue-600 hover:text-blue-500 font-medium transition-colors duration-200">
try again
</button>
</p>
</div>
</div>
</body>
</html>
Key Features:
Responsive Design: Works perfectly on mobile and desktop
Modern Aesthetics: Glassmorphism effects with gradient backgrounds and smooth shadows
Alpine.js Interactivity: Real-time validation, loading states, and smooth transitions
Email Validation: Client-side validation with helpful error messages
Loading Animation: Spinning loader during form submission
Success State: Animated success message with option to send to different email
Micro-interactions: Hover effects, scale animations, and smooth transitions
Technical Highlights:
Uses Alpine.js for reactive data and form handling
Tailwind CSS for modern styling with custom gradients
Form validation with real-time feedback
Simulated API call with loading states
Accessible form design with proper labels and focus states
Clean animation transitions using Alpine.js directives
The form includes email validation, loading states, success messaging, and a clean user experience with smooth animations throughout the interaction flow.