Want a login page that feels fresh, friendly, and fast? Here’s a simple, clear guide to use your existing code to publish a polished educational login screen with motion, gradients, and built-in form checks.
What this page includes
-
Two-panel layout: A colorful, animated left side and a clean login form on the right for focus and clarity.
-
Tailwind via CDN: No build tools needed; the page pulls Tailwind from a CDN.
-
Micro-animations: Custom
bounce
,pulse
, andspin
keyframes add gentle motion to shapes and icons. -
Glass card form: A soft, “glass” effect around the inputs makes the form feel premium.
-
Form UX details: Email + password fields, show/hide password toggle, “Remember me,” helpful error text, and a loading spinner on submit.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>EduPlatform - Student Login</title>
<script src="https://cdn.tailwindcss.com"></script>
<style>
/* Custom animations */
@keyframes bounce {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-10px); }
}
@keyframes pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.5; }
}
@keyframes spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
.animate-bounce { animation: bounce 2s infinite; }
.animate-pulse { animation: pulse 2s infinite; }
.animate-spin { animation: spin 10s linear infinite; }
/* Animation delays */
.delay-500 { animation-delay: 0.5s; }
.delay-1000 { animation-delay: 1s; }
.delay-1500 { animation-delay: 1.5s; }
.delay-2000 { animation-delay: 2s; }
/* Backdrop blur effect */
.backdrop-blur-sm { backdrop-filter: blur(4px); }
.backdrop-blur-lg { backdrop-filter: blur(16px); }
.backdrop-blur-xl { backdrop-filter: blur(24px); }
/* Drop shadow */
.drop-shadow { filter: drop-shadow(0 4px 6px rgba(0, 0, 0, 0.1)); }
.drop-shadow-lg { filter: drop-shadow(0 10px 15px rgba(0, 0, 0, 0.1)); }
/* Custom gradients */
.bg-gradient-student {
background: linear-gradient(135deg, #ddd6fe 0%, #c7d2fe 100%);
}
.bg-gradient-skin {
background: linear-gradient(135deg, #fbbf24 0%, #f59e0b 100%);
}
.bg-gradient-hair {
background: linear-gradient(135deg, #92400e 0%, #78350f 100%);
}
.bg-gradient-shirt {
background: linear-gradient(135deg, #3b82f6 0%, #1d4ed8 100%);
}
.bg-gradient-backpack {
background: linear-gradient(135deg, #ef4444 0%, #dc2626 100%);
}
.bg-gradient-pants {
background: linear-gradient(135deg, #4b5563 0%, #374151 100%);
}
/* Loading spinner */
.spinner {
border: 3px solid rgba(255, 255, 255, 0.3);
border-top: 3px solid white;
border-radius: 50%;
width: 20px;
height: 20px;
animation: spin 1s linear infinite;
}
/* Form enhancements */
.form-input:focus {
border-color: #8b5cf6;
box-shadow: 0 0 0 4px rgba(139, 92, 246, 0.2);
}
.form-input.error {
border-color: #ef4444;
box-shadow: 0 0 0 4px rgba(239, 68, 68, 0.2);
}
/* Button hover effects */
.btn-primary {
background: linear-gradient(135deg, #6366f1 0%, #8b5cf6 50%, #ec4899 100%);
transition: all 0.3s ease;
}
.btn-primary:hover {
background: linear-gradient(135deg, #4f46e5 0%, #7c3aed 50%, #db2777 100%);
transform: scale(1.05);
}
.btn-primary:active {
transform: scale(0.95);
}
/* Glass morphism effect */
.glass {
background: rgba(255, 255, 255, 0.9);
backdrop-filter: blur(24px);
border: 2px solid rgba(255, 255, 255, 0.6);
}
/* Mobile responsive */
@media (max-width: 768px) {
.student-illustration {
width: 80px !important;
height: 80px !important;
}
}
</style>
</head>
<body>
<div class="min-h-screen bg-white relative overflow-hidden">
<!-- Animated background shapes -->
<div class="absolute inset-0 overflow-hidden">
<div class="absolute -top-40 -right-40 w-80 h-80 bg-gradient-to-br from-yellow-400 to-orange-500 rounded-full opacity-20 animate-pulse"></div>
<div class="absolute -bottom-40 -left-40 w-96 h-96 bg-gradient-to-tr from-green-400 to-blue-500 rounded-full opacity-20 animate-bounce"></div>
<div class="absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 w-64 h-64 bg-gradient-to-r from-purple-400 to-pink-400 rounded-full opacity-10 animate-pulse"></div>
</div>
<!-- Enhanced floating colorful graphics -->
<div class="absolute inset-0 pointer-events-none">
<div class="absolute top-20 left-10 text-yellow-400 opacity-60 animate-bounce">
<svg width="32" height="32" viewBox="0 0 24 24" fill="currentColor">
<path d="M12 2l2.09 6.26L22 9.27l-5 4.87L18.18 22 12 18.77 5.82 22 7 14.14l-5-4.87 7.91-1.01L12 2z"/>
</svg>
</div>
<div class="absolute top-32 right-16 text-indigo-500 opacity-70 animate-bounce">
<svg width="32" height="32" viewBox="0 0 24 24" fill="currentColor">
<path d="M4 6h16l-1 12H5L4 6zm1-2h14v2H5V4z"/>
</svg>
</div>
<div class="absolute top-40 right-20 text-green-400 opacity-60 animate-bounce">
<svg width="40" height="40" viewBox="0 0 24 24" fill="currentColor">
<circle cx="12" cy="8" r="6"/>
<path d="M15.5 21a.5.5 0 0 1-.5-.5v-2a.5.5 0 0 1 .5-.5h2a.5.5 0 0 1 .5.5v2a.5.5 0 0 1-.5.5h-2z"/>
</svg>
</div>
<div class="absolute bottom-32 left-20 text-cyan-400 opacity-70 animate-pulse">
<svg width="24" height="24" viewBox="0 0 24 24" fill="currentColor">
<path d="M12 2l3.09 6.26L22 9.27l-5 4.87L18.18 22 12 18.77 5.82 22 7 14.14l-5-4.87 7.91-1.01L12 2z"/>
</svg>
</div>
<!-- Additional Graphics Layer -->
<div class="absolute top-10 left-1/4 text-pink-500 opacity-40 animate-spin">
<svg width="30" height="30" viewBox="0 0 30 30">
<path d="M15 2 L20 12 L28 10 L22 18 L30 22 L18 20 L20 28 L12 22 L8 30 L10 18 L2 20 L8 12 L0 8 L12 10 L10 2 Z" fill="currentColor"/>
</svg>
</div>
<div class="absolute top-60 left-20 text-emerald-500 opacity-50 animate-pulse">
<svg width="24" height="24" viewBox="0 0 24 24">
<rect x="4" y="6" width="16" height="12" rx="2" fill="currentColor" opacity="0.6"/>
<rect x="6" y="4" width="12" height="2" rx="1" fill="currentColor"/>
<circle cx="10" cy="12" r="2" fill="white"/>
<circle cx="14" cy="12" r="2" fill="white"/>
</svg>
</div>
</div>
<div class="flex min-h-screen">
<!-- Left Side - Colorful Graphics Area -->
<div class="hidden md:flex md:w-1/2 relative bg-gradient-to-br from-indigo-600 via-purple-600 to-pink-600 overflow-hidden">
<!-- Enhanced animated background elements with more graphics -->
<div class="absolute inset-0">
<div class="absolute top-20 left-20 w-40 h-40 bg-gradient-to-r from-yellow-400 to-orange-500 rounded-full opacity-20 animate-pulse"></div>
<div class="absolute bottom-32 right-16 w-56 h-56 bg-gradient-to-r from-green-400 to-cyan-500 rounded-full opacity-15 animate-bounce"></div>
<div class="absolute top-1/2 left-10 w-32 h-32 bg-gradient-to-r from-pink-400 to-red-500 rounded-full opacity-25 animate-pulse"></div>
<div class="absolute top-10 right-1/3 w-24 h-24 bg-gradient-to-r from-cyan-400 to-blue-500 rounded-full opacity-20 animate-bounce"></div>
<!-- Additional geometric shapes -->
<div class="absolute top-40 left-40 w-16 h-16 bg-gradient-to-br from-purple-500 to-pink-500 transform rotate-45 opacity-15 animate-spin"></div>
<div class="absolute bottom-20 left-1/3 w-20 h-20 bg-gradient-to-tr from-indigo-400 to-purple-500 rounded-full opacity-20 animate-pulse"></div>
<!-- Mathematical symbols -->
<div class="absolute top-32 left-1/2 text-6xl font-bold text-blue-300 opacity-10 animate-bounce">∑</div>
<div class="absolute bottom-1/3 right-20 text-5xl font-bold text-green-300 opacity-15 animate-pulse">π</div>
<div class="absolute top-2/3 left-16 text-4xl font-bold text-purple-300 opacity-10 animate-bounce">∞</div>
<!-- School-related graphics -->
<div class="absolute top-16 right-40 opacity-10 animate-pulse">
<svg width="60" height="60" viewBox="0 0 60 60">
<rect x="10" y="15" width="40" height="30" rx="3" fill="#3b82f6" opacity="0.6"/>
<rect x="15" y="10" width="30" height="8" rx="2" fill="#1d4ed8"/>
<circle cx="25" cy="25" r="3" fill="white"/>
<circle cx="35" cy="25" r="3" fill="white"/>
<rect x="20" y="35" width="20" height="2" fill="white"/>
</svg>
</div>
</div>
<!-- Main content -->
<div class="relative z-10 flex flex-col items-center justify-center p-12 text-center">
<!-- Enhanced study illustration with animated student -->
<div class="mb-8 relative">
<div class="w-72 h-72 bg-gradient-to-br from-white to-cyan-100 bg-opacity-20 rounded-full flex items-center justify-center backdrop-blur-lg border-2 border-white border-opacity-30 shadow-2xl">
<div class="text-center space-y-6">
<!-- Realistic Animated Student with Bag - SVG -->
<div class="relative mx-auto student-illustration" style="width: 100px; height: 100px;">
<svg width="100" height="100" viewBox="0 0 100 100" class="animate-bounce drop-shadow-lg">
<!-- Background circle for student -->
<circle cx="50" cy="50" r="45" fill="url(#studentBg)" opacity="0.1"/>
<!-- Definitions for gradients -->
<defs>
<linearGradient id="studentBg" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#ddd6fe" />
<stop offset="100%" stop-color="#c7d2fe" />
</linearGradient>
<linearGradient id="skinTone" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#fbbf24" />
<stop offset="100%" stop-color="#f59e0b" />
</linearGradient>
<linearGradient id="hairColor" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#92400e" />
<stop offset="100%" stop-color="#78350f" />
</linearGradient>
<linearGradient id="shirtColor" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#3b82f6" />
<stop offset="100%" stop-color="#1d4ed8" />
</linearGradient>
<linearGradient id="backpackColor" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#ef4444" />
<stop offset="100%" stop-color="#dc2626" />
</linearGradient>
<linearGradient id="pantsColor" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#4b5563" />
<stop offset="100%" stop-color="#374151" />
</linearGradient>
</defs>
<!-- Backpack (behind student) -->
<g class="animate-pulse delay-200">
<rect x="55" y="25" width="18" height="25" rx="3" fill="url(#backpackColor)" stroke="#b91c1c" stroke-width="1"/>
<!-- Backpack straps -->
<line x1="57" y1="25" x2="52" y2="35" stroke="#6b7280" stroke-width="2" stroke-linecap="round"/>
<line x1="71" y1="25" x2="64" y2="35" stroke="#6b7280" stroke-width="2" stroke-linecap="round"/>
<!-- Backpack details -->
<rect x="58" y="28" width="12" height="8" rx="1" fill="#b91c1c" opacity="0.8"/>
<rect x="60" y="38" width="8" height="6" rx="1" fill="#dc2626"/>
<!-- Backpack buckles -->
<circle cx="59" cy="27" r="1" fill="#fbbf24"/>
<circle cx="69" cy="27" r="1" fill="#fbbf24"/>
</g>
<!-- Head -->
<circle cx="50" cy="25" r="8" fill="url(#skinTone)" stroke="#f59e0b" stroke-width="0.5"/>
<!-- Hair -->
<path d="M42 20 Q50 15 58 20 Q58 22 56 24 Q50 19 44 24 Q42 22 42 20 Z" fill="url(#hairColor)"/>
<!-- Eyes -->
<circle cx="47" cy="24" r="1.5" fill="#1f2937"/>
<circle cx="53" cy="24" r="1.5" fill="#1f2937"/>
<circle cx="47" cy="24" r="0.5" fill="white"/>
<circle cx="53" cy="24" r="0.5" fill="white"/>
<!-- Nose -->
<ellipse cx="50" cy="26" rx="0.5" ry="1" fill="#f59e0b" opacity="0.6"/>
<!-- Mouth -->
<path d="M48 28 Q50 29 52 28" stroke="#92400e" stroke-width="1" fill="none" stroke-linecap="round"/>
<!-- Neck -->
<rect x="48" y="32" width="4" height="3" fill="url(#skinTone)"/>
<!-- Body/Shirt -->
<rect x="44" y="35" width="12" height="20" rx="2" fill="url(#shirtColor)" stroke="#1d4ed8" stroke-width="0.5"/>
<!-- Shirt collar -->
<path d="M44 37 L50 40 L56 37" stroke="white" stroke-width="1.5" fill="none"/>
<!-- Shirt buttons -->
<circle cx="50" cy="42" r="0.8" fill="white" opacity="0.8"/>
<circle cx="50" cy="47" r="0.8" fill="white" opacity="0.8"/>
<!-- Arms -->
<ellipse cx="41" cy="42" rx="3" ry="8" fill="url(#skinTone)" transform="rotate(-15 41 42)"/>
<ellipse cx="59" cy="42" rx="3" ry="8" fill="url(#skinTone)" transform="rotate(15 59 42)"/>
<!-- Hands -->
<circle cx="38" cy="48" r="2" fill="url(#skinTone)"/>
<circle cx="62" cy="48" r="2" fill="url(#skinTone)"/>
<!-- Pants -->
<rect x="44" y="55" width="12" height="15" rx="1" fill="url(#pantsColor)" stroke="#374151" stroke-width="0.5"/>
<!-- Belt -->
<rect x="44" y="55" width="12" height="2" fill="#92400e"/>
<rect x="49" y="55" width="2" height="2" fill="#fbbf24"/>
<!-- Legs -->
<ellipse cx="47" cy="75" rx="2.5" ry="10" fill="url(#skinTone)"/>
<ellipse cx="53" cy="75" rx="2.5" ry="10" fill="url(#skinTone)"/>
<!-- Shoes -->
<ellipse cx="47" cy="85" rx="4" ry="3" fill="#1f2937"/>
<ellipse cx="53" cy="85" rx="4" ry="3" fill="#1f2937"/>
<ellipse cx="47" cy="84" rx="3" ry="2" fill="#374151"/>
<ellipse cx="53" cy="84" rx="3" ry="2" fill="#374151"/>
<!-- Shoe laces -->
<line x1="45" y1="83" x2="49" y2="83" stroke="white" stroke-width="0.5"/>
<line x1="51" y1="83" x2="55" y2="83" stroke="white" stroke-width="0.5"/>
</svg>
<!-- Floating educational elements around student -->
<div class="absolute -top-2 -left-6 animate-pulse">
<svg width="20" height="24" viewBox="0 0 20 24" class="drop-shadow">
<rect x="2" y="2" width="16" height="20" rx="1" fill="#10b981" stroke="#059669" stroke-width="1"/>
<rect x="4" y="0" width="12" height="4" rx="0.5" fill="#34d399"/>
<line x1="5" y1="8" x2="15" y2="8" stroke="white" stroke-width="0.5"/>
<line x1="5" y1="11" x2="15" y2="11" stroke="white" stroke-width="0.5"/>
<line x1="5" y1="14" x2="12" y2="14" stroke="white" stroke-width="0.5"/>
</svg>
</div>
<div class="absolute -top-4 -right-4 animate-bounce delay-500">
<svg width="16" height="20" viewBox="0 0 16 20" class="drop-shadow">
<rect x="1" y="1" width="14" height="18" rx="1" fill="#8b5cf6" stroke="#7c3aed" stroke-width="1"/>
<rect x="3" y="0" width="10" height="3" rx="0.5" fill="#a78bfa"/>
<line x1="4" y1="6" x2="12" y2="6" stroke="white" stroke-width="0.4"/>
<line x1="4" y1="9" x2="12" y2="9" stroke="white" stroke-width="0.4"/>
<line x1="4" y1="12" x2="10" y2="12" stroke="white" stroke-width="0.4"/>
</svg>
</div>
</div>
<div class="flex justify-center space-x-4">
<div class="bg-gradient-to-r from-green-400 to-cyan-500 p-2 rounded-full">
<svg width="32" height="32" viewBox="0 0 24 24" fill="white">
<path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2H6.5A2.5 2.5 0 0 1 4 4.5v15z"/>
</svg>
</div>
<div class="bg-gradient-to-r from-indigo-400 to-purple-500 p-2 rounded-full">
<svg width="32" height="32" viewBox="0 0 24 24" fill="white">
<path d="M4 6h16l-1 12H5L4 6zm1-2h14v2H5V4z"/>
</svg>
</div>
<div class="bg-gradient-to-r from-pink-400 to-purple-500 p-2 rounded-full">
<svg width="32" height="32" viewBox="0 0 24 24" fill="white">
<path d="M16 4c0-1.11.89-2 2-2s2 .89 2 2-.89 2-2 2-2-.89-2-2zM4 18v-4h3v4h2v-7.5c0-1.1.9-2 2-2s2 .9 2 2V18h2v-4h3v4h2V8.5c0-1.1-.9-2-2-2h-5c-1.1 0-2 .9-2 2V18H4z"/>
</svg>
</div>
<div class="bg-gradient-to-r from-orange-400 to-red-500 p-2 rounded-full">
<svg width="32" height="32" viewBox="0 0 24 24" fill="white">
<polyline points="23,6 13.5,15.5 8.5,10.5 1,18" stroke="white" stroke-width="2" fill="none"/>
</svg>
</div>
</div>
</div>
</div>
</div>
<div class="space-y-6 max-w-md">
<h1 class="text-5xl font-bold text-white leading-tight drop-shadow-lg">
<span class="bg-gradient-to-r from-yellow-300 to-orange-300 bg-clip-text text-transparent">Transform</span> Your Learning Journey
</h1>
<p class="text-xl text-cyan-100 leading-relaxed drop-shadow">
Join thousands of students and professionals advancing their skills with our
<span class="text-yellow-300 font-semibold"> comprehensive learning platform</span>.
</p>
<!-- Enhanced stats with colors -->
<div class="grid grid-cols-3 gap-6 pt-8">
<div class="text-center bg-white bg-opacity-10 rounded-2xl p-4 backdrop-blur-sm border border-white border-opacity-20">
<div class="text-3xl font-bold bg-gradient-to-r from-yellow-300 to-orange-300 bg-clip-text text-transparent">50K+</div>
<div class="text-cyan-200 text-sm font-medium">Students</div>
</div>
<div class="text-center bg-white bg-opacity-10 rounded-2xl p-4 backdrop-blur-sm border border-white border-opacity-20">
<div class="text-3xl font-bold bg-gradient-to-r from-green-300 to-cyan-300 bg-clip-text text-transparent">1000+</div>
<div class="text-cyan-200 text-sm font-medium">Courses</div>
</div>
<div class="text-center bg-white bg-opacity-10 rounded-2xl p-4 backdrop-blur-sm border border-white border-opacity-20">
<div class="text-3xl font-bold bg-gradient-to-r from-pink-300 to-purple-300 bg-clip-text text-transparent">95%</div>
<div class="text-cyan-200 text-sm font-medium">Success Rate</div>
</div>
</div>
</div>
</div>
</div>
<!-- Right Side - Enhanced Login Form -->
<div class="w-full md:w-1/2 flex items-center justify-center p-6 sm:p-8 lg:p-12 relative">
<!-- Mobile header with colors -->
<div class="md:hidden absolute top-8 left-1/2 transform -translate-x-1/2">
<div class="flex items-center gap-2 bg-white bg-opacity-20 rounded-full px-4 py-2 backdrop-blur-sm">
<div class="bg-gradient-to-r from-indigo-500 to-purple-600 p-1 rounded-full">
<svg width="24" height="24" viewBox="0 0 24 24" fill="white">
<path d="M22 10v6M2 10l10-5 10 5-10 5z"/>
<path d="M6 12v5c3 0 9 1 9-5"/>
</svg>
</div>
<span class="text-xl font-bold bg-gradient-to-r from-indigo-600 to-purple-600 bg-clip-text text-transparent">EduPlatform</span>
</div>
</div>
<div class="w-full max-w-md space-y-8">
<!-- Colorful Header -->
<div class="text-center space-y-3">
<h2 class="text-4xl font-bold bg-gradient-to-r from-indigo-600 via-purple-600 to-pink-600 bg-clip-text text-transparent">
Welcome back
</h2>
<p class="text-gray-700 text-lg">Sign in to continue your <span class="text-purple-600 font-semibold">learning adventure</span></p>
</div>
<!-- Enhanced Login Form -->
<div class="glass rounded-3xl shadow-2xl p-8 space-y-6">
<!-- Email field -->
<div class="space-y-2">
<label for="email" class="block text-sm font-semibold text-gray-700">
Email address
</label>
<div class="relative group">
<div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
<div class="bg-gradient-to-r from-indigo-500 to-purple-600 p-1 rounded-full">
<svg width="12" height="12" viewBox="0 0 24 24" fill="white">
<path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z"/>
<polyline points="22,6 12,13 2,6"/>
</svg>
</div>
</div>
<input
type="email"
id="email"
name="email"
class="form-input block w-full pl-12 pr-3 py-4 border-2 border-purple-200 rounded-xl focus:outline-none transition-all duration-300 bg-white bg-opacity-80 text-gray-900 placeholder-gray-500 font-medium"
placeholder="Enter your email"
/>
</div>
<p id="email-error" class="text-sm text-red-600 font-medium hidden"></p>
</div>
<!-- Password field -->
<div class="space-y-2">
<label for="password" class="block text-sm font-semibold text-gray-700">
Password
</label>
<div class="relative group">
<div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
<div class="bg-gradient-to-r from-indigo-500 to-purple-600 p-1 rounded-full">
<svg width="12" height="12" viewBox="0 0 24 24" fill="white">
<rect x="3" y="11" width="18" height="11" rx="2" ry="2"/>
<circle cx="12" cy="7" r="4"/>
<path d="M12 1v6"/>
</svg>
</div>
</div>
<input
type="password"
id="password"
name="password"
class="form-input block w-full pl-12 pr-12 py-4 border-2 border-purple-200 rounded-xl focus:outline-none transition-all duration-300 bg-white bg-opacity-80 text-gray-900 placeholder-gray-500 font-medium"
placeholder="Enter your password"
/>
<button
type="button"
id="toggle-password"
class="absolute inset-y-0 right-0 pr-3 flex items-center"
>
<div class="bg-gradient-to-r from-gray-400 to-gray-500 p-1 rounded-full hover:from-purple-400 hover:to-pink-500 transition-all duration-300">
<svg width="12" height="12" viewBox="0 0 24 24" fill="white" id="eye-icon">
<path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/>
<circle cx="12" cy="12" r="3"/>
</svg>
</div>
</button>
</div>
<p id="password-error" class="text-sm text-red-600 font-medium hidden"></p>
</div>
<!-- Remember me and forgot password -->
<div class="flex items-center justify-between">
<label class="flex items-center">
<input
type="checkbox"
class="w-5 h-5 text-purple-600 bg-purple-100 border-purple-300 rounded focus:ring-purple-500 focus:ring-2"
/>
<span class="ml-3 text-sm text-gray-700 font-medium">Remember me</span>
</label>
<button
type="button"
class="text-sm bg-gradient-to-r from-indigo-600 to-purple-600 bg-clip-text text-transparent font-bold hover:from-purple-600 hover:to-pink-600 transition-all duration-300"
>
Forgot password?
</button>
</div>
<!-- Submit button -->
<button
type="button"
id="signin-btn"
class="btn-primary w-full py-4 px-6 rounded-xl font-bold text-lg text-white focus:outline-none focus:ring-4 focus:ring-purple-300 transition-all duration-300 flex items-center justify-center gap-3 shadow-xl hover:shadow-2xl"
>
<svg width="20" height="20" viewBox="0 0 24 24" fill="white">
<path d="M12 2l3.09 6.26L22 9.27l-5 4.87L18.18 22 12 18.77 5.82 22 7 14.14l-5-4.87 7.91-1.01L12 2z"/>
</svg>
Sign in
<svg width="20" height="20" viewBox="0 0 24 24" fill="white">
<polyline points="9,18 15,12 9,6"/>
</svg>
</button>
</div>
<!-- Sign up link -->
<div class="text-center">
<p class="text-gray-700 text-lg">
Don't have an account?
<button class="bg-gradient-to-r from-indigo-600 to-purple-600 bg-clip-text text-transparent font-bold hover:from-purple-600 hover:to-pink-600 transition-all duration-300">
Sign up for free ✨
</button>
</p>
</div>
</div>
</div>
</div>
</div>
<script>
// Form validation and interactions
const emailInput = document.getElementById('email');
const passwordInput = document.getElementById('password');
const emailError = document.getElementById('email-error');
const passwordError = document.getElementById('password-error');
const signinBtn = document.getElementById('signin-btn');
const togglePasswordBtn = document.getElementById('toggle-password');
const eyeIcon = document.getElementById('eye-icon');
let isLoading = false;
let showPassword = false;
// Email validation
emailInput.addEventListener('input', function() {
const email = this.value;
if (email && !/\S+@\S+\.\S+/.test(email)) {
this.classList.add('error');
emailError.textContent = 'Please enter a valid email';
emailError.classList.remove('hidden');
} else {
this.classList.remove('error');
emailError.classList.add('hidden');
}
});
// Password validation
passwordInput.addEventListener('input', function() {
const password = this.value;
if (password && password.length < 6) {
this.classList.add('error');
passwordError.textContent = 'Password must be at least 6 characters';
passwordError.classList.remove('hidden');
} else {
this.classList.remove('error');
passwordError.classList.add('hidden');
}
});
// Toggle password visibility
togglePasswordBtn.addEventListener('click', function() {
showPassword = !showPassword;
passwordInput.type = showPassword ? 'text' : 'password';
if (showPassword) {
eyeIcon.innerHTML = '<path d="M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19m-6.72-1.07a3 3 0 1 1-4.24-4.24"/><line x1="1" y1="1" x2="23" y2="23"/>';
} else {
eyeIcon.innerHTML = '<path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/>';
}
});
// Form submission
signinBtn.addEventListener('click', async function() {
const email = emailInput.value;
const password = passwordInput.value;
// Validate form
let hasErrors = false;
if (!email) {
emailInput.classList.add('error');
emailError.textContent = 'Email is required';
emailError.classList.remove('hidden');
hasErrors = true;
} else if (!/\S+@\S+\.\S+/.test(email)) {
emailInput.classList.add('error');
emailError.textContent = 'Please enter a valid email';
emailError.classList.remove('hidden');
hasErrors = true;
}
if (!password) {
passwordInput.classList.add('error');
passwordError.textContent = 'Password is required';
passwordError.classList.remove('hidden');
hasErrors = true;
} else if (password.length < 6) {
passwordInput.classList.add('error');
passwordError.textContent = 'Password must be at least 6 characters';
passwordError.classList.remove('hidden');
hasErrors = true;
}
if (hasErrors) return;
// Show loading state
isLoading = true;
this.disabled = true;
this.innerHTML = '<div class="spinner"></div>';
// Simulate API call
setTimeout(() => {
isLoading = false;
this.disabled = false;
this.innerHTML = `
<svg width="20" height="20" viewBox="0 0 24 24" fill="white">
<path d="M12 2l3.09 6.26L22 9.27l-5 4.87L18.18 22 12 18.77 5.82 22 7 14.14l-5-4.87 7.91-1.01L12 2z"/>
</svg>
Sign in
<svg width="20" height="20" viewBox="0 0 24 24" fill="white">
<polyline points="9,18 15,12 9,6"/>
</svg>
`;
console.log('Login attempt:', { email, password });
alert('Login successful! (Demo)');
}, 2000);
});
</script>
</body>
</html>
How it’s structured
-
Animated Hero (Left):
Gradient circles, geometric shapes, school icons, and a bouncing student illustration create a lively, campus vibe without heavy images. They’re positioned absolutely and animated with your custom keyframes to keep the DOM light. -
Login Card (Right):
A glass-styled card holds labeled inputs, a strong “Sign in” button with gradient hover, and friendly microcopy (“Welcome back”). Icons next to inputs guide the eye and reinforce purpose. -
Responsive by default:
On desktop, it’s a two-column split; on mobile, the hero tucks away and the form takes the full width, keeping performance smooth.
The finishing touches you already have
-
Focus & error states: Inputs add a purple glow on focus; clear messages show for invalid email or short passwords. This prevents blank submits and guides the user gently.
-
Password toggle: The eye icon switches between hidden/visible states and updates the SVG path so the control feels alive.
-
Loading feedback: The “Sign in” button becomes a spinner during the fake API call, then returns to normal—great for real endpoints later.
How to brand it
-
Colors & gradients: Update the gradient ranges (indigo → your brand palette) and the hero shapes to match your school or product colors.
-
Copy & tone: Change headline and subtext to your voice (“Welcome to EduPortal,” “Learn. Grow. Achieve.”).
-
Logo & icons: Replace the SVG badges and header emblem with your logo for instant familiarity.
Hooking up real authentication
Your HTML already simulates a network call. Swap the timeout with your real auth:
-
Custom backend: POST email/password to your
/api/login
, then route on success. -
Auth services: Connect to Firebase, Supabase, or your OAuth provider.
Keep it safe: always use HTTPS, never log passwords, and throttle repeated clicks while submitting.
Accessibility & performance tips
-
Every input has a label and meaningful error text. Keep the
aria
roles polite and ensure keyboard focus rings are visible. -
CSS animations are light; avoid stacking too many high-opacity blurs on low-end devices. Test on a phone to confirm smoothness.
Summary
This template gives you a ready-to-brand, responsive login page with tasteful motion and thoughtful UX. Drop it into your project, tweak colors and text, and wire up your auth—your users will land in a space that feels modern, trusted, and genuinely educational.