You know those One Time Password inputs? The UI is typically 4 or 6 numbers with individual inputs. Just from today…
![](https://i0.wp.com/frontendmasters.com/blog/wp-content/uploads/2025/02/IMG_2817.png?resize=764%2C1024&ssl=1)
![](https://i0.wp.com/frontendmasters.com/blog/wp-content/uploads/2025/02/Screenshot-2025-02-04-at-9.10.08%E2%80%AFAM.png?resize=1024%2C534&ssl=1)
Brad Frost was blogging about them recently. They certainly have some issue! Here’s one he spells out that I agree with wholeheartedly:
I don’t like the pattern where each digit is its own text box. It’s an affordance that’s supposed to make things clearer, but it doesn’t (for me at least). Can I paste? Where do I paste? Is my paste going to carry over into all of the little boxes? Half the time there’s a dash in the code; does that get included?
It’s awfully tricky to get right, considering the user confusion that can happen before you’re interacting with those little boxes. And once you are, the experience better be awfully accommodating.
A while back I read an article by Phuoc Nguyen about them called Build an OTP input field. I’d say all-in-all, Phuoc did a good job. The design and user experience was considered, like using the arrow keys to move between the inputs and handling “paste”. I’d say accessibility too but I feel like this is complicated enough of an interaction I can’t personally vouch for that.
But I’m also also like — damn — that’s complicated. That’s a lot of JavaScript code. Why is this so hard? And what would happen without JavaScript? Seems like it would be a pretty gnarly experience. A particular thing that makes it hard is making each character a separate <input />
in the HTML.
<div class="otp">
<input type="text" maxlength="1" />
<input type="text" maxlength="1" />
<input type="text" maxlength="1" />
<input type="text" maxlength="1" />
</div>
Code language: HTML, XML (xml)
That complicates validation, input, pasting, accessibility, navigation… literally everything.
And then I was like… why can’t this just be one input? The rectangles behind the numbers is just visual theater. Just a bit of trendy decoration. It’s just a styling concern, not a semantic, usability, or any other concern.
So I was like… I’m just gonna make those rectangles background-image
s and see if that works. So I built a demo, but it had a flaw: as you typed the last character, the value would kinda slide one direction and look bad. You can see it here.
But I posed the challenge in our ShopTalk Discord and others had some ideas. Josh Collingsworth had an idea where you could cover up some area at the end and prevent the movement issue (the yellow block would be white or whatever covers up properly). Alex Fimion did it a smidge cleaner by covering the last bit with background-image
instead of a pseudo-element. Here’s that:
Is that better than the 4-inputs approach?
I’m giving an only-slightly-hesitant thumbs up 👍. My hesitation is that in order for this to look right, there is a lot of “magic number” usage. That is, numbers that are just visually tweaked by hand to make it all work, and based on finicky things like font metrics (which might change over time and with different fonts) rather than hard foundational layout.
So let’s call this a pretty good take. I think when you consider the HTML used alone you can see using a one-input approach feels best:
<input
required
type="text"
autocomplete="one-time-code"
inputmode="numeric"
maxlength="4"
pattern="\d{4}"
>
Code language: HTML, XML (xml)
In fact, if I started having problems with the look of the “rectangles behind the numbers” approach, I’d just make it a big ol’ single input without the individual rectangles. Like I said, I feel those are just something of a design trend anyway.
What does AI want to do?
Just as a fun little exercise, I used the very generic prompt create a 4 digit PIN input UI
with zero rounds of feedback/iteration across a number of different scaffolding tools.
![](https://i0.wp.com/frontendmasters.com/blog/wp-content/uploads/2025/02/Screenshot-2025-02-05-at-1.58.26%E2%80%AFPM.png?resize=1024%2C726&ssl=1)
![](https://i0.wp.com/frontendmasters.com/blog/wp-content/uploads/2025/02/Screenshot-2025-02-05-at-2.01.50%E2%80%AFPM.png?resize=1024%2C871&ssl=1)
![](https://i0.wp.com/frontendmasters.com/blog/wp-content/uploads/2025/02/Screenshot-2025-02-05-at-2.03.15%E2%80%AFPM.png?resize=1024%2C663&ssl=1)
![](https://i0.wp.com/frontendmasters.com/blog/wp-content/uploads/2025/02/Screenshot-2025-02-05-at-2.04.34%E2%80%AFPM.png?resize=1024%2C761&ssl=1)
I’m fairly confident that if you provided a more elaborate prompt with more specific requirements and were willing to go through rounds of iteration, you could get what you want out of these tools. I just found it interesting that by default, based on the code they were trained on, that what you get tends to focus on using multiple inputs, not to mention a heap of tools you don’t ask for.
I made something similar using gradients without a lot of magic numbers but CSS variables to control everything: https://css-tip.com/single-digit-inputs/
Your solution looks cleaner to me