One Time Password - JS + CSS
One Time Password
Contoh Penggunaan
Section titled “Contoh Penggunaan”Verifikasi Nomor Ponsel
Kode OTP telah di kirim ke nomor ponsel +6282•-••••-1029
Kode tidak terkirim?
<section>
<div class="p-4 border border-gray-300 rounded w-fit">
<!-- Manual recreation of OneTimePassword layout in Vanilla HTML -->
<div class="flex flex-col gap-2 relative">
<div>
<h4 class="text-sm font-semibold text-content-primary mb-1">Verifikasi Nomor Ponsel</h4>
<p class="text-xs text-content-tertiary">
Kode OTP telah di kirim ke nomor ponsel +6282•-••••-1029
</p>
</div>
<div class="flex gap-2 w-full mt-4" id="otp-js-container">
<input
type="text"
maxlength="1"
class="w-12 h-14 text-center rounded-lg border border-neutral-300 text-lg focus:border-interactive-active focus:ring-1 focus:ring-interactive-active focus:outline-none focus:shadow-sm"
/>
<input
type="text"
maxlength="1"
class="w-12 h-14 text-center rounded-lg border border-neutral-300 text-lg focus:border-interactive-active focus:ring-1 focus:ring-interactive-active focus:outline-none focus:shadow-sm"
/>
<input
type="text"
maxlength="1"
class="w-12 h-14 text-center rounded-lg border border-neutral-300 text-lg focus:border-interactive-active focus:ring-1 focus:ring-interactive-active focus:outline-none focus:shadow-sm"
/>
<input
type="text"
maxlength="1"
class="w-12 h-14 text-center rounded-lg border border-neutral-300 text-lg focus:border-interactive-active focus:ring-1 focus:ring-interactive-active focus:outline-none focus:shadow-sm"
/>
<input
type="text"
maxlength="1"
class="w-12 h-14 text-center rounded-lg border border-neutral-300 text-lg focus:border-interactive-active focus:ring-1 focus:ring-interactive-active focus:outline-none focus:shadow-sm"
/>
<input
type="text"
maxlength="1"
class="w-12 h-14 text-center rounded-lg border border-neutral-300 text-lg focus:border-interactive-active focus:ring-1 focus:ring-interactive-active focus:outline-none focus:shadow-sm"
/>
</div>
<!-- Error Message Placement -->
<span class="text-xs text-negative-600 hidden mt-1" id="otp-error-message"></span>
</div>
<p class="flex flex-row gap-x-2 mt-4 items-center">
Kode tidak terkirim?
<button
type="button"
class="ina-button ina-button--link ina-button--md p-0 h-auto text-sm"
id="otp-send-code"
>
<span class="ina-button__text" id="otp-send-text">Kirim Kode</span>
</button>
</p>
<!-- MSG COMPLETION -->
<p id="otp-completion-msg" class="mt-2 font-medium hidden text-green-600"></p>
</div>
</section>
<script is:inline>
document.addEventListener('DOMContentLoaded', () => {
const container = document.getElementById('otp-js-container');
const inputs = container ? Array.from(container.querySelectorAll('input')) : [];
const sendBtn = document.getElementById('otp-send-code');
const sendText = document.getElementById('otp-send-text');
const msgLabel = document.getElementById('otp-completion-msg');
let isCounting = false;
let timeLeft = 0;
let countdownInterval;
if (sendBtn) {
sendBtn.addEventListener('click', () => {
if (isCounting) return;
console.log('Kode: 123456');
isCounting = true;
timeLeft = 60;
sendBtn.classList.add('text-neutral-400', 'cursor-not-allowed', 'pointer-events-none');
countdownInterval = setInterval(() => {
timeLeft -= 1;
if (sendText) sendText.textContent = `Kirim ulang dalam ${timeLeft} detik`;
if (timeLeft <= 0) {
clearInterval(countdownInterval);
isCounting = false;
if (sendText) sendText.textContent = 'Kirim Kode';
sendBtn.classList.remove(
'text-neutral-400',
'cursor-not-allowed',
'pointer-events-none'
);
}
}, 1000);
});
}
if (inputs.length > 0) {
inputs.forEach((input, index) => {
input.addEventListener('input', (e) => {
// Allow only numbers
e.target.value = e.target.value.replace(/[^0-9]/g, '');
if (e.target.value && index < inputs.length - 1) {
inputs[index + 1].focus();
}
checkCompletion();
});
input.addEventListener('keydown', (e) => {
if (e.key === 'Backspace' && !e.target.value && index > 0) {
inputs[index - 1].focus();
inputs[index - 1].value = '';
}
});
});
inputs[0].addEventListener('paste', (e) => {
e.preventDefault();
const pastedData = e.clipboardData
.getData('text')
.replace(/[^0-9]/g, '')
.slice(0, 6);
for (let i = 0; i < pastedData.length; i++) {
if (inputs[i]) {
inputs[i].value = pastedData[i];
}
}
if (pastedData.length > 0 && pastedData.length < 6) {
inputs[pastedData.length].focus();
} else if (pastedData.length === 6) {
inputs[5].focus();
}
checkCompletion();
});
}
function checkCompletion() {
const code = inputs.map((i) => i.value).join('');
if (code.length === 6) {
if (code === '123456') {
if (msgLabel) {
msgLabel.textContent = 'Sukses kode OTP Berhasil';
msgLabel.className = 'mt-2 font-medium text-green-600 block';
}
} else {
if (msgLabel) {
msgLabel.textContent = 'Kode OTP salah.';
msgLabel.className = 'mt-2 font-medium text-red-600 block';
}
}
} else {
if (msgLabel) {
msgLabel.className = 'mt-2 font-medium hidden';
}
}
}
});
</script>