Created
November 13, 2025 18:19
-
-
Save amit08255/2fae9ea28b39b96a73f94d0b95cb774a to your computer and use it in GitHub Desktop.
HTML OTP Input
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <!DOCTYPE html> | |
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1"> | |
| <title>Verify Your Account</title> | |
| <style> | |
| body { | |
| font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; | |
| background: #f5f5f5; | |
| margin: 0; | |
| padding: 20px; | |
| display: flex; | |
| justify-content: center; | |
| align-items: center; | |
| min-height: 100vh; | |
| } | |
| .container { | |
| background: white; | |
| padding: 40px; | |
| border-radius: 12px; | |
| box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); | |
| width: 100%; | |
| max-width: 400px; | |
| } | |
| h1 { | |
| font-size: 24px; | |
| margin: 0 0 8px 0; | |
| color: #333; | |
| } | |
| .intro-text { | |
| font-size: 14px; | |
| color: #666; | |
| margin-bottom: 24px; | |
| } | |
| .form-group { | |
| display: flex; | |
| flex-direction: column; | |
| gap: 12px; | |
| margin-bottom: 20px; | |
| } | |
| label { | |
| font-size: 14px; | |
| font-weight: 500; | |
| color: #333; | |
| } | |
| .otp-input { | |
| font-size: 32px; | |
| letter-spacing: 8px; | |
| text-align: center; | |
| padding: 16px; | |
| border: 2px solid #ddd; | |
| border-radius: 8px; | |
| font-family: 'Monaco', 'Courier New', monospace; | |
| transition: all 0.2s; | |
| } | |
| .otp-input:focus { | |
| outline: none; | |
| border-color: #007AFF; | |
| box-shadow: 0 0 0 3px rgba(0, 122, 255, 0.1); | |
| } | |
| .otp-input:invalid:not(:placeholder-shown) { | |
| border-color: #FF3B30; | |
| } | |
| .hint-text { | |
| font-size: 12px; | |
| color: #666; | |
| margin: 0; | |
| } | |
| .error-message { | |
| color: #FF3B30; | |
| font-size: 13px; | |
| margin-top: 8px; | |
| display: none; | |
| } | |
| .success-message { | |
| color: #34C759; | |
| font-size: 13px; | |
| margin-top: 8px; | |
| display: none; | |
| } | |
| .submit-btn { | |
| padding: 12px 24px; | |
| background: #007AFF; | |
| color: white; | |
| border: none; | |
| border-radius: 8px; | |
| font-size: 16px; | |
| font-weight: 600; | |
| cursor: pointer; | |
| width: 100%; | |
| transition: background 0.2s; | |
| } | |
| .submit-btn:hover { | |
| background: #0051D5; | |
| } | |
| .submit-btn:disabled { | |
| background: #ccc; | |
| cursor: not-allowed; | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="container"> | |
| <h1>Verify Your Account</h1> | |
| <p class="intro-text"> | |
| We sent a 6-digit code to your authenticator app. Paste it here or type it in. | |
| </p> | |
| <form id="otp-form"> | |
| <div class="form-group"> | |
| <label for="otp-input"> | |
| One-time passcode | |
| </label> | |
| <input | |
| id="otp-input" | |
| type="text" | |
| inputmode="numeric" | |
| autocomplete="one-time-code" | |
| maxlength="6" | |
| pattern="[0-9]{6}" | |
| required | |
| class="otp-input" | |
| placeholder="000000" | |
| /> | |
| <p class="hint-text"> | |
| 6 digits. Paste works. Password managers work. | |
| </p> | |
| <p class="error-message" id="error-msg"></p> | |
| <p class="success-message" id="success-msg"></p> | |
| </div> | |
| <button type="submit" class="submit-btn">Verify Code</button> | |
| </form> | |
| </div> | |
| <script> | |
| const form = document.getElementById('otp-form'); | |
| const input = document.getElementById('otp-input'); | |
| const errorMsg = document.getElementById('error-msg'); | |
| const successMsg = document.getElementById('success-msg'); | |
| const submitBtn = form.querySelector('button'); | |
| form.addEventListener('submit', async (e) => { | |
| e.preventDefault(); | |
| errorMsg.style.display = 'none'; | |
| successMsg.style.display = 'none'; | |
| const code = input.value.trim(); | |
| if (!code.match(/^[0-9]{6}$/)) { | |
| errorMsg.textContent = 'Enter exactly 6 digits.'; | |
| errorMsg.style.display = 'block'; | |
| return; | |
| } | |
| submitBtn.disabled = true; | |
| try { | |
| const response = await fetch('/verify-otp', { | |
| method: 'POST', | |
| headers: { 'Content-Type': 'application/json' }, | |
| body: JSON.stringify({ code }) | |
| }); | |
| if (response.ok) { | |
| successMsg.textContent = 'Code verified. Redirecting...'; | |
| successMsg.style.display = 'block'; | |
| setTimeout(() => window.location.href = '/dashboard', 1500); | |
| } else { | |
| errorMsg.textContent = 'Invalid code. Try again.'; | |
| errorMsg.style.display = 'block'; | |
| input.value = ''; | |
| input.focus(); | |
| } | |
| } catch (err) { | |
| errorMsg.textContent = 'Network error. Please try again.'; | |
| errorMsg.style.display = 'block'; | |
| } finally { | |
| submitBtn.disabled = false; | |
| } | |
| }); | |
| input.focus(); | |
| </script> | |
| </body> | |
| </html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment