HTML & CSS for a One-Time Password Input
HTML & CSS for a One-Time Password Input ź“ė Ø
You know those One Time Password inputs? The UI is typically 4 or 6 numbers with individual inputs. Just from todayā¦


Brad Frost was blogging about them recently. They certainly have some issue! Hereās one he spells out that I agree with wholeheartedly:
The UX of login codes | Brad Frost bradfrost.com
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>
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. (chriscoyier
)
But I posed the challenge in our ShopTalk Discord and others had some ideas. Josh Collingsworth had an idea (collinsworth
) 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}"
>
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.




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.