I have an OTP input that consists of 8 one digit inputs this image and when I move between these digit inputs by x-on:keyup
, always the first input is focused and value is selected for a moment then moves to next input.
to get the problem clearly, also watch this video
Component:
<div class="flex w-full content-center">
<form x-transition wire:submit.prevent.throttle.1000ms="verifyotp()" class="w-full">
<div x-data="{digitinputnumber : 1}" class="w-full px-4 grid gap-4">
<div class="flex items-center mb-4 dark:text-white">
<span class="bg-slate-100 dark:bg-gray-500 rounded p-1 ml-1">
<x-icon.shield-check/>
</span>
<h3>{{ __('messages.login.enter-otp') }}</h3>
</div>
<div class="flex gap-2 ltr justify-center">
<div>
<input x-model="d1" select-none x-on:click="digitinputnumber = 1" x-on:keyup="if($event.key != 'Backspace' && 0 <= d1 && d1 <= 9) {digitinputnumber = digitinputnumber + 1} else {}" x-trap="digitinputnumber == 1 ? true : false" x-mask="9" type="text" class="p-2 w-12 aspect-square text-center ltr text-xl rounded-lg">
</div>
<div>
<input x-model="d2" x-on:click="digitinputnumber = 2" x-on:keyup="if($event.key != 'Backspace' && 0 <= d2 && d2 <= 9) {digitinputnumber = digitinputnumber + 1} else {digitinputnumber = digitinputnumber - 1}" x-trap="digitinputnumber == 2 ? true : false" x-mask="9" type="text" class="p-2 w-12 aspect-square text-center ltr text-xl rounded-lg">
</div>
<div>
<input x-model="d3" x-on:click="digitinputnumber = 3" x-on:keyup="if($event.key != 'Backspace' && 0 <= d3 && d3 <= 9) {digitinputnumber = digitinputnumber + 1} else {digitinputnumber = digitinputnumber - 1}" x-trap.="digitinputnumber == 3 ? true : false" x-mask="9" type="text" class="p-2 w-12 aspect-square text-center ltr text-xl rounded-lg">
</div>
<div>
<input x-model="d4" x-on:click="digitinputnumber = 4" x-on:keyup="if($event.key != 'Backspace' && 0 <= d4 && d4 <= 9) {digitinputnumber = digitinputnumber + 1} else {digitinputnumber = digitinputnumber - 1}" x-trap="digitinputnumber == 4 ? true : false" x-mask="9" type="text" class="p-2 w-12 aspect-square text-center ltr text-xl rounded-lg">
</div>
<div>
<input x-model="d5" x-on:click="digitinputnumber = 5" x-on:keyup="if($event.key != 'Backspace' && 0 <= d5 && d5 <= 9) {digitinputnumber = digitinputnumber + 1} else {digitinputnumber = digitinputnumber - 1}" x-trap="digitinputnumber == 5 ? true : false"x-mask="9" type="text" class="p-2 w-12 aspect-square text-center ltr text-xl rounded-lg">
</div>
<div>
<input x-model="d6" x-on:click="digitinputnumber = 6" x-on:keyup="if($event.key != 'Backspace' && 0 <= d6 && d6 <= 9) {digitinputnumber = digitinputnumber + 1} else {digitinputnumber = digitinputnumber - 1}" x-trap="digitinputnumber == 6 ? true : false" x-mask="9" type="text" class="p-2 w-12 aspect-square text-center ltr text-xl rounded-lg">
</div>
<div>
<input x-model="d7" x-on:click="digitinputnumber = 7" x-on:keyup="if($event.key != 'Backspace' && 0 <= d7 && d7 <= 9) {digitinputnumber = digitinputnumber + 1} else {digitinputnumber = digitinputnumber - 1}" x-trap="digitinputnumber == 7 ? true : false" x-mask="9" type="text" class="p-2 w-12 aspect-square text-center ltr text-xl rounded-lg">
</div>
<div>
<input x-model="d8" x-on:click="digitinputnumber = 8" x-on:keyup="if($event.key != 'Backspace' && 0 <= d8 && d8 <= 9) {} else {digitinputnumber = digitinputnumber - 1}" x-trap="digitinputnumber == 8 ? true : false" x-mask="9" type="text" class="p-2 w-12 aspect-square text-center ltr text-xl rounded-lg">
</div>
</div>
</div>
</form>
</div>
I had not get answer in git hub discussions of livewire and alpine, also I couldn't find answers in documentation or web forums.
I actually don't understand why my code was not working, but I changed to code below and every thing OK!
I should use x-ref
and focus()
to handle this type of input, maybe it's bug of Alpine JS or some thing I don't now.
Also you can use x-for
to make it better, but I prefer not to do.
<div class="flex w-full content-center">
<form x-transition wire:submit.prevent.throttle.1000ms="verifyotp()" class="w-full">
<div class="w-full px-4 grid gap-4">
<div class="flex items-center mb-4 dark:text-white">
<span class="bg-slate-100 dark:bg-gray-500 rounded p-1 ml-1">
<x-icon.shield-check/>
</span>
<h3>{{ __('messages.login.enter-otp') }}</h3>
</div>
<div class="flex gap-2 ltr justify-center">
<div>
<input x-ref="d1" x-on:keyup="if($event.key != 'Backspace') {$refs.d2.focus()} else {}" x-mask="9" type="text" class="p-2 w-12 aspect-square text-center ltr text-xl rounded-lg" autofocus>
</div>
<div>
<input x-ref="d2" x-on:keyup="if($event.key != 'Backspace') {$refs.d3.focus()} else {$refs.d1.focus()}" x-mask="9" type="text" class="p-2 w-12 aspect-square text-center ltr text-xl rounded-lg">
</div>
<div>
<input x-ref="d3" x-on:keyup="if($event.key != 'Backspace') {$refs.d4.focus()} else {$refs.d2.focus()}" x-mask="9" type="text" class="p-2 w-12 aspect-square text-center ltr text-xl rounded-lg">
</div>
<div>
<input x-ref="d4" x-on:keyup="if($event.key != 'Backspace') {$refs.d5.focus()} else {$refs.d3.focus()}" x-mask="9" type="text" class="p-2 w-12 aspect-square text-center ltr text-xl rounded-lg">
</div>
<div>
<input x-ref="d5" x-on:keyup="if($event.key != 'Backspace') {$refs.d6.focus()} else {$refs.d4.focus()}" x-mask="9" type="text" class="p-2 w-12 aspect-square text-center ltr text-xl rounded-lg">
</div>
<div>
<input x-ref="d6" x-on:keyup="if($event.key != 'Backspace') {$refs.d7.focus()} else {$refs.d5.focus()}" x-mask="9" type="text" class="p-2 w-12 aspect-square text-center ltr text-xl rounded-lg">
</div>
<div>
<input x-ref="d7" x-on:keyup="if($event.key != 'Backspace') {$refs.d8.focus()} else {$refs.d6.focus()}" x-mask="9" type="text" class="p-2 w-12 aspect-square text-center ltr text-xl rounded-lg">
</div>
<div>
<input x-ref="d8" x-on:keyup="if($event.key != 'Backspace') {} else {$refs.d7.focus()}" x-mask="9" type="text" class="p-2 w-12 aspect-square text-center ltr text-xl rounded-lg">
</div>
</div>
</div>
</form>