diff --git a/OTP Input Field/demo1/README.md b/OTP Input Field/demo1/README.md new file mode 100644 index 0000000..e2150e4 --- /dev/null +++ b/OTP Input Field/demo1/README.md @@ -0,0 +1 @@ +- [Medium Blog Link](https://sqkhor.medium.com/create-an-otp-input-with-javascript-c0c9f7c610fe) diff --git a/OTP Input Field/demo1/demo.html b/OTP Input Field/demo1/demo.html new file mode 100644 index 0000000..dd2b95d --- /dev/null +++ b/OTP Input Field/demo1/demo.html @@ -0,0 +1,64 @@ + + + + + + OTP Input Field - Using JS + + + +
+ + + + + + +
+ + + + + diff --git a/OTP Input Field/demo1/script.js b/OTP Input Field/demo1/script.js new file mode 100644 index 0000000..fc76dd0 --- /dev/null +++ b/OTP Input Field/demo1/script.js @@ -0,0 +1,100 @@ +function updateInput() { + let inputValue = Array.from(inputs).reduce(function (otp, input) { + otp += (input.value.length) ? input.value : ' '; + return otp; + }, ""); + document.querySelector("input[name=otp]").value = inputValue; +} + +window.onload = () => { + const inputs = document.querySelectorAll("#otp-input input"); + + for (let i = 0; i < inputs.length; i++) { + const input = inputs[i]; + + input.addEventListener("input", function () { + // handling normal input + if (input.value.length == 1 && i + 1 < inputs.length) { + inputs[i + 1].focus(); + } + + // if a value is pasted, put each character to each of the next input + if (input.value.length > 1) { + // sanities input + if (isNaN(input.value)) { + input.value = ""; + updateInput(); + return; + } + + // split characters to array + const chars = input.value.split(''); + + for (let pos = 0; pos < chars.length; pos++) { + // if length exceeded the number of inputs, stop + if (pos + i >= inputs.length) break; + + // paste value + let targetInput = inputs[pos + i]; + targetInput.value = chars[pos]; + } + + // focus the input next to the last pasted character + let focus_index = Math.min(inputs.length - 1, i + chars.length); + inputs[focus_index].focus(); + } + updateInput(); + }); + + input.addEventListener("keydown", function (e) { + // backspace button + if (e.keyCode == 8 && input.value == '' && i != 0) { + // shift next values towards the left + for (let pos = i; pos < inputs.length - 1; pos++) { + inputs[pos].value = inputs[pos + 1].value; + } + + // clear previous box and focus on it + inputs[i - 1].value = ''; + inputs[i - 1].focus(); + updateInput(); + return; + } + + // delete button + if (e.keyCode == 46 && i != inputs.length - 1) { + // shift next values towards the left + for (let pos = i; pos < inputs.length - 1; pos++) { + inputs[pos].value = inputs[pos + 1].value; + } + + // clear the last box + inputs[inputs.length - 1].value = ''; + input.select(); + e.preventDefault(); + updateInput(); + return; + } + + // left button + if (e.keyCode == 37) { + if (i > 0) { + e.preventDefault(); + inputs[i - 1].focus(); + inputs[i - 1].select(); + } + return; + } + + // right button + if (e.keyCode == 39) { + if (i + 1 < inputs.length) { + e.preventDefault(); + inputs[i + 1].focus(); + inputs[i + 1].select(); + } + return; + } + }); + } +}; \ No newline at end of file diff --git a/OTP Input Field/demo1/style.css b/OTP Input Field/demo1/style.css new file mode 100644 index 0000000..ab72ca9 --- /dev/null +++ b/OTP Input Field/demo1/style.css @@ -0,0 +1,29 @@ +* { + margin: 0; + padding: 0; + box-size: border-box; +} + +#otp-input { + display: flex; + gap: 0.5em; +} + +#otp-input input { + width: 2em; + padding: 0.5em 0; + font-family: monospace; + font-size: 1em; + text-align: center; +} + +/* hide spinner */ +#otp-input input::-webkit-outer-spin-button, +#otp-input input::-webkit-inner-spin-button { + -webkit-appearance: none; + margin: 0; +} + +#otp-input input[type="number"] { + -moz-appearance: textfield; /* Firefox */ +} diff --git a/OTP Input Field/demo2/README.md b/OTP Input Field/demo2/README.md new file mode 100644 index 0000000..59f021c --- /dev/null +++ b/OTP Input Field/demo2/README.md @@ -0,0 +1 @@ +- [Blog Link](https://chriscoyier.net/2023/12/04/html-css-for-a-one-time-password-input/) diff --git a/OTP Input Field/demo2/demo.html b/OTP Input Field/demo2/demo.html new file mode 100644 index 0000000..43e530c --- /dev/null +++ b/OTP Input Field/demo2/demo.html @@ -0,0 +1,19 @@ + + + + + + OTP Input Field - Without using JS + + + + + + diff --git a/OTP Input Field/demo2/style.css b/OTP Input Field/demo2/style.css new file mode 100644 index 0000000..7dd0374 --- /dev/null +++ b/OTP Input Field/demo2/style.css @@ -0,0 +1,34 @@ +[autocomplete="one-time-code"] { + --magic-number: 100px; + + background-image: linear-gradient(#fff, #fff), + url("https://assets.codepen.io/3/rounded-rectangle.svg"); + background-size: var(--magic-number); + background-position-x: right, left; + background-repeat: no-repeat, repeat-x; + border: 0; + height: var(--magic-number); + width: calc(5 * var(--magic-number)); + font-size: calc(0.6 * var(--magic-number)); + font-family: monospace; + letter-spacing: calc(0.64 * var(--magic-number)); + padding-inline-start: calc(0.3 * var(--magic-number)); + box-sizing: border-box; + overflow: hidden; + transform: translatex(calc(0.5 * var(--magic-number))); +} +[autocomplete="one-time-code"]:focus { + outline: none; + background-image: linear-gradient(#fff, #fff), + url("https://assets.codepen.io/729148/blue-rounded-rectangle.svg"); + background-size: var(--magic-number); + background-position-x: right, left; + background-repeat: no-repeat, repeat-x; +} + +body { + height: 100vh; + margin: 0; + display: grid; + place-items: center; +} diff --git a/OTP Input Field/index.html b/OTP Input Field/index.html new file mode 100644 index 0000000..72d8f13 --- /dev/null +++ b/OTP Input Field/index.html @@ -0,0 +1,44 @@ + + + + + + + OTP Input Field + + + + + Demo 1(Using JS) + Demo 2(Without using JS) + diff --git a/Scroll Triggered Animations/index.html b/Scroll Triggered Animations/index.html index 9f72e24..f681741 100644 --- a/Scroll Triggered Animations/index.html +++ b/Scroll Triggered Animations/index.html @@ -1,47 +1,45 @@ - - - - - - JavaScript Experiments + + + + + Scroll Triggered Animations - + - - - Demo 1 - Demo 2 - Demo 3 - \ No newline at end of file + + Demo 1 + Demo 2 + Demo 3 + diff --git a/index.html b/index.html index 199af10..3e721e4 100644 --- a/index.html +++ b/index.html @@ -96,5 +96,6 @@ Custom Dropdown Markdown to HTML Audio Visualizer + OTP Input Field