Simple One-Time Passcode Inputs
If you’ve signed into an online service in the last decade, chances are you’ve been asked to fill a one-time passcode (“OTP”) field with a handful of digits from a text, email or authenticator app:

Despite the prevalence of this pattern, it seems to cause plenty of anxiety in otherwise level-headed web developers… especially if they’ve fixated on the current trend of segmenting the input to convey the passcode’s length (a new spin on the ol’ input mask).
Why else would so many tumble down the rabbit hole of building their own <input> replacement, stringing multiple <input> elements together, or burdening their project with yet another third-party dependency?
If you find yourself in a similar situation, I have good news! You can ship a fully functional OTP input today without any CSS hacks or JavaScript frameworks.
All you need is some HTML.
Basic Markup
A single <input> element: That’s where the OTP magic happens!
<input type="text"
inputmode="numeric"
autocomplete="one-time-code"
maxlength="6">Code language: HTML, XML (xml)
Let’s break down each of its attributes:
- Even though our passcode will consist of numbers, it isn’t actually a number: A value of
000004should not be the considered the same as a value of4. For that reason, we follow the HTML spec and settype="text". inputmode="numeric"enables a numeric virtual keyboard on touch devices.autocomplete="one-time-code"adds support for autofill from password managers or via SMS.maxlength="6"prevents visitors from typing too many characters.
We can opt into client-side validation by adding two more:
<input type="text"
inputmode="numeric"
autocomplete="one-time-code"
maxlength="6"
pattern="\d{6}"
required>
Code language: HTML, XML (xml)
pattern defines the code we expect, in this case exactly six ({6}) numeric digits (\d). required tells the browser this field must have a value that satisfies the pattern.
Example: In a Form
Now all our OTP-specific features are accounted for, but an input is meaningless without context. Let’s fix that by building out a full form with a heading, a label, a submit button and a support link in case something goes wrong:
<form action="…" method="post">
<h2>Verify Account</h2>
<label for="otp">
Enter the 6-digit numeric code sent to +1 (555) 555-5555
</label>
<input type="text"
id="otp"
inputmode="numeric"
autocomplete="one-time-code"
maxlength="6"
pattern="\d{6}"
required>
<button>
Continue
</button>
<a href="…">
Try another way…
</a>
</form>Code language: HTML, XML (xml)
Note how the label specifies the intended length and format of the passcode. No input mask, icon or visual affordance can match the accessibility and clarity of straightforward text!
And with that, our OTP pattern is functionally complete!
Demo: With Styles
Since we’ve covered all the critical functionality in our HTML, we’re free to style our form however the project dictates.
In this example, I’ve chosen a large, monospaced font with some letter-spacing to keep every digit of the code distinct and readable. I’m also using the :invalid pseudo class to reduce the visual prominence of the <button> element until the code is valid:
Demo: Enhanced
Having a solid foundation in HTML and CSS alone doesn’t preclude us from leveraging JavaScript, too.
Here’s the same demo as before, but with a simple input mask web component to indicate remaining characters:
Because this builds atop existing patterns instead of replacing them outright, the code is tiny: Less than a kilobyte without any optimization or compression.
Takeaways
- All critical features of a one-time passcode input are possible using HTML alone.
- Clear labels and instructive text are more important than any visual affordance.
- Custom design and behavior can be layered on as progressive enhancements.
- This approach is quicker to implement and avoids many common performance and accessibility pitfalls.

Tyler Sticka has over 20 years of experience designing interfaces for the web and beyond. He co-owns Cloud Four, where he provides multidisciplinary creative direction for a variety of organizations. He’s also an artist, writer, speaker and developer. You can follow Tyler on his personal site, Mastodon or Bluesky.