-
Embossed mobile OTP login UI
HTML
CSS
JavaScript
🔐
Secure Login
Login securely using your mobile number
Mobile Number
Send OTP
Enter 6 Digit OTP
Verify OTP
Didn't receive OTP?
Resend in 30s
/* ======================================== ROOT COLORS======================================== */ :root { --bg: #111827; --surface: #111827; --text: #f8fafc; --muted: #94a3b8; --primary: #00b4ff; --primary-dark: #0077ff; --success: #22c55e; --error: #ff4d6d; --shadow-dark: rgba(0, 0, 0, 0.65); --shadow-light: rgba(55, 65, 81, 0.35); } /* ======================================== RESET======================================== */ * { margin: 0; padding: 0; box-sizing: border-box; } /* ======================================== BODY======================================== */ body { min-height: 100vh; display: flex; justify-content: center; align-items: center; font-family: Arial, Helvetica, sans-serif; background: radial-gradient(circle at 10% 10%, #1e293b 0%, #111827 45%, #070b12 100%); overflow: hidden; } /* ======================================== BACKGROUND GLOW======================================== */ body::before { content: ""; position: fixed; width: 350px; height: 350px; border-radius: 50%; background: rgba(0, 180, 255, 0.08); filter: blur(80px); top: -120px; left: -100px; pointer-events: none; } body::after { content: ""; position: fixed; width: 300px; height: 300px; border-radius: 50%; background: rgba(0, 119, 255, 0.07); filter: blur(80px); bottom: -120px; right: -100px; pointer-events: none; } /* ======================================== LOGIN CARD======================================== */ .login-container { position: relative; width: 390px; padding: 42px 30px; border-radius: 32px; background: var(--surface); border: 1px solid rgba(255, 255, 255, 0.04); box-shadow: 20px 20px 45px var(--shadow-dark), -10px -10px 30px var(--shadow-light); text-align: center; z-index: 2; animation: cardAppear 0.7s ease; } @keyframes cardAppear { from { opacity: 0; transform: translateY(30px) scale(.95); } to { opacity: 1; transform: translateY(0) scale(1); } } /* ======================================== LOGO======================================== */ .logo { width: 82px; height: 82px; margin: 0 auto 22px; display: flex; justify-content: center; align-items: center; border-radius: 50%; background: var(--surface); color: var(--primary); font-size: 34px; box-shadow: inset 8px 8px 16px rgba(0, 0, 0, .6), inset -8px -8px 16px rgba(55, 65, 81, .35), 0 0 25px rgba(0, 180, 255, .08); text-shadow: 0 0 10px rgba(0, 180, 255, .9), 0 0 25px rgba(0, 180, 255, .45); animation: logoFloat 3s ease-in-out infinite; } @keyframes logoFloat { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-6px); } } /* ======================================== HEADING======================================== */ h2 { color: var(--text); font-size: 26px; margin-bottom: 8px; letter-spacing: .5px; } .subtitle { color: var(--muted); font-size: 14px; line-height: 1.6; margin-bottom: 30px; } /* ======================================== FORM======================================== */ .form-group { margin-bottom: 22px; text-align: left; } label { display: block; color: #cbd5e1; font-size: 13px; font-weight: bold; margin-bottom: 9px; } /* ======================================== MOBILE INPUT======================================== */ .input-box { width: 100%; height: 56px; padding: 0 18px; border: none; outline: none; border-radius: 16px; background: var(--surface); color: var(--text); font-size: 16px; box-shadow: inset 7px 7px 14px rgba(0, 0, 0, .58), inset -7px -7px 14px rgba(55, 65, 81, .35); transition: .3s ease; } .input-box::placeholder { color: #64748b; } .input-box:focus { transform: translateY(-2px); box-shadow: inset 3px 3px 7px rgba(0, 0, 0, .6), inset -3px -3px 7px rgba(55, 65, 81, .35), 0 0 0 2px rgba(0, 180, 255, .25), 0 0 25px rgba(0, 180, 255, .12); } /* ======================================== OTP SECTION======================================== */ #otpSection { display: none; animation: otpAppear .5s ease; } @keyframes otpAppear { from { opacity: 0; transform: translateY(25px) scale(.94); } to { opacity: 1; transform: translateY(0) scale(1); } } /* ======================================== OTP BOX CONTAINER======================================== */ .otp-container { display: flex; justify-content: space-between; gap: 8px; } /* ======================================== OTP INPUT======================================== */ .otp { width: 47px; height: 57px; border: none; outline: none; border-radius: 14px; background: var(--surface); color: var(--primary); text-align: center; font-size: 21px; font-weight: bold; box-shadow: inset 6px 6px 12px rgba(0, 0, 0, .58), inset -6px -6px 12px rgba(55, 65, 81, .35); transition: transform .25s ease, box-shadow .25s ease; } .otp:focus { transform: translateY(-5px) scale(1.05); box-shadow: inset 2px 2px 5px rgba(0, 0, 0, .6), inset -2px -2px 5px rgba(55, 65, 81, .35), 0 0 15px rgba(0, 180, 255, .5), 0 0 30px rgba(0, 180, 255, .12); } /* ======================================== BUTTON======================================== */ .btn { width: 100%; height: 56px; border: none; border-radius: 16px; background: linear-gradient(135deg, #00b4ff, #0077ff); color: #fff; font-size: 16px; font-weight: bold; cursor: pointer; box-shadow: 8px 8px 18px rgba(0, 0, 0, .55), -5px -5px 12px rgba(55, 65, 81, .25), 0 0 20px rgba(0, 180, 255, .18); transition: .25s ease; } .btn:hover { transform: translateY(-3px); box-shadow: 8px 12px 22px rgba(0, 0, 0, .6), 0 0 28px rgba(0, 180, 255, .4); } .btn:active { transform: translateY(2px); box-shadow: inset 5px 5px 10px rgba(0, 0, 0, .35), 0 0 10px rgba(0, 180, 255, .2); } /* ======================================== RESEND======================================== */ .resend { margin-top: 18px; color: var(--muted); font-size: 13px; } .resend span { color: var(--primary); font-weight: bold; cursor: pointer; transition: .2s ease; } .resend span:hover { text-shadow: 0 0 10px rgba(0, 180, 255, .8); } /* ======================================== DEMO OTP======================================== */ .demo-otp { margin-top: 15px; padding: 11px; border-radius: 13px; background: var(--surface); color: var(--muted); font-size: 13px; box-shadow: inset 4px 4px 8px rgba(0, 0, 0, .55), inset -4px -4px 8px rgba(55, 65, 81, .35); } .demo-otp strong { color: var(--primary); letter-spacing: 2px; text-shadow: 0 0 8px rgba(0, 180, 255, .5); } /* ======================================== MESSAGE======================================== */ .message { min-height: 22px; margin-top: 17px; font-size: 14px; font-weight: bold; } .success { color: var(--success); text-shadow: 0 0 10px rgba(34, 197, 94, .35); } .error { color: var(--error); text-shadow: 0 0 10px rgba(255, 77, 109, .35); } /* ======================================== SHAKE======================================== */ .shake { animation: shake .4s ease; } @keyframes shake { 0%, 100% { transform: translateX(0); } 25% { transform: translateX(-8px); } 50% { transform: translateX(8px); } 75% { transform: translateX(-5px); } } /* ======================================== SUCCESS PULSE======================================== */ .success-animation { animation: successPulse .7s ease; } @keyframes successPulse { 0% { transform: scale(1); } 50% { transform: scale(1.035); } 100% { transform: scale(1); } } /* ======================================== MOBILE======================================== */ @media(max-width: 450px) { body { padding: 15px; } .login-container { width: 100%; padding: 35px 20px; border-radius: 27px; } .otp-container { gap: 6px; } .otp { width: 43px; height: 54px; font-size: 19px; } h2 { font-size: 24px; } } @media(max-width: 350px) { .otp { width: 39px; height: 50px; font-size: 18px; } .otp-container { gap: 4px; } }
const DEMO_OTP = "123456"; let countdown = 30; let timer; function sendOTP() { const mobile = document.getElementById("mobile"); const number = mobile.value.trim(); if (!/^[0-9]{10}$/.test(number)) { showMessage( "Please enter a valid 10 digit mobile number", "error" ); mobile.classList.add("shake"); setTimeout(() => { mobile.classList.remove("shake"); }, 400); return; } document .getElementById("mobileSection") .style.display = "none"; document .getElementById("otpSection") .style.display = "block"; showMessage( "✓ OTP sent successfully", "success" ); startTimer(); document .querySelector(".otp") .focus(); } const otpInputs = document.querySelectorAll(".otp"); otpInputs.forEach( (input, index) => { input.addEventListener( "input", function() { this.value = this.value.replace( /[^0-9]/g, "" ); if ( this.value && index < otpInputs.length - 1 ) { otpInputs[ index + 1 ].focus(); } } ); input.addEventListener( "keydown", function(e) { if ( e.key === "Backspace" && !this.value && index > 0 ) { otpInputs[ index - 1 ].focus(); } } ); input.addEventListener( "paste", function(e) { e.preventDefault(); const pasted = ( e.clipboardData || window.clipboardData ) .getData("text") .replace( /[^0-9]/g, "" ) .slice(0, 6); pasted .split("") .forEach( (digit, i) => { if ( otpInputs[i] ) { otpInputs[i] .value = digit; } } ); if ( pasted.length === 6 ) { otpInputs[5] .focus(); } } ); } ); function verifyOTP() { let enteredOTP = ""; otpInputs.forEach( input => { enteredOTP += input.value; } ); if ( enteredOTP.length !== 6 ) { showMessage( "Please enter the complete 6 digit OTP", "error" ); shakeOTP(); return; } if ( enteredOTP === DEMO_OTP ) { showMessage( "✓ OTP verified successfully! Login successful.", "success" ); document .getElementById("loginBox") .classList.add( "success-animation" ); otpInputs.forEach( input => { input.disabled = true; } ); clearInterval(timer); document .getElementById("resendText") .style.display = "none"; } else { showMessage( "✕ Invalid OTP. Please try again.", "error" ); shakeOTP(); } } function shakeOTP() { const container = document.getElementById( "otpContainer" ); container.classList.add( "shake" ); setTimeout(() => { container.classList.remove( "shake" ); }, 400); } function startTimer() { countdown = 30; clearInterval(timer); const resend = document.getElementById( "resendText" ); resend.style.pointerEvents = "none"; resend.textContent = `Resend in ${countdown}s`; timer = setInterval( () => { countdown--; resend.textContent = `Resend in ${countdown}s`; if ( countdown <= 0 ) { clearInterval(timer); resend.textContent = "Resend OTP"; resend.style.pointerEvents = "auto"; } }, 1000 ); } document .getElementById("resendText") .addEventListener( "click", function() { if ( countdown > 0 ) { return; } otpInputs.forEach( input => { input.value = ""; } ); showMessage( "✓ New OTP sent successfully", "success" ); startTimer(); otpInputs[0] .focus(); } ); function showMessage( text, type ) { const message = document.getElementById( "message" ); message.textContent = text; message.className = "message " + type; }
Live Preview