Skip to Content

Blog > Best Practices for MFA input

Best Practices for MFA input

Karl Groves. - 28/10/2026

A six-digit verification code should be easy to enter. Yet many multifactor authentication (MFA) interfaces turn that simple task into six separate form fields, each with its own label, focus behavior, and editing rules.

Those individual boxes may look tidy, but they can complicate keyboard navigation, screen reader use, pasting, and autofill. The strongest default is simpler: use one input for the entire verification code.

Use a single input

Consider this common implementation:

<div>
  <input autocomplete="off" aria-label="Please enter OTP character 1"
         inputmode="numeric" type="tel">
  <input autocomplete="off" aria-label="Please enter OTP character 2"
         inputmode="numeric" type="tel">
  <input autocomplete="off" aria-label="Please enter OTP character 3"
         inputmode="numeric" type="tel">
  <input autocomplete="off" aria-label="Please enter OTP character 4"
         inputmode="numeric" type="tel">
  <input autocomplete="off" aria-label="Please enter OTP character 5"
         inputmode="numeric" type="tel">
  <input autocomplete="off" aria-label="Please enter OTP character 6"
         inputmode="numeric" type="tel">
</div>

Each input has an accessible name, which is useful. But accessible names alone do not make the overall interaction easy to use. In this scenario, users encounter six separate controls to complete one task. Screen reader users hear repetitive instructions. Developers must implement additional behavior to handle pasting a complete code, replacing digits, deleting characters, and moving between fields. Autofill also becomes more complicated.

A single input gives users one tab stop and the familiar editing behavior of a standard text field. They can enter, paste, select, and replace the complete code.

If the design calls for six visual boxes, that appearance can be built around one real input. Preserve a visible focus indicator, caret, and selection so the visual treatment does not obscure how the control works.

Choose the right HTML attributes

For a six-digit numeric code, start with a conventional form:

<form action="/verify" method="post">
  <label for="verification-code">Verification code</label>

  <p id="code-help">
    Enter the 6-digit code we sent to your phone.
  </p>

  <input
    id="verification-code"
    name="verification-code"
    type="text"
    inputmode="numeric"
    autocomplete="one-time-code"
    pattern="[0-9]{6}"
    aria-describedby="code-help"
    required
  >

  <button type="submit">Verify code</button>
</form>

These attributes each serve a different purpose:

  • type="text" treats the code as text and preserves leading zeros. A verification code is neither a telephone number nor a quantity.
  • inputmode="numeric" requests a numeric keyboard on devices that support it. It does not enforce numeric input.
  • autocomplete="one-time-code" identifies the field’s purpose and enables code suggestions in supporting browsers and operating systems.
  • pattern="[0-9]{6}" specifies the expected format for browser validation. It does not prevent users from entering other characters.
  • aria-describedby="code-help" associates the instructions with the input.

These input attributes align with Google’s guidance for SMS verification forms. Autofill support varies, so manual entry and pasting must remain usable.

The example assumes a numeric code. If your codes contain letters, adapt the instructions and validation, and remove the numeric keyboard hint.

Use visible, understandable labels

“Verification code” is easier to understand than “OTP character 1.”

Use a visible label so everyone can identify the field, including people using speech input or magnification. Put supporting information in visible instructions: how many characters the code contains and where the user should find it.

For example: “Enter the 6-digit code we sent to your phone.”

Avoid making an accessible label carry information that sighted users also need. An aria-label can name a control, but it does not provide visible instructions.

Support pasting and autofill

Users should be able to copy a complete code from a message or password manager and paste it into the field. Do not block clipboard actions or require users to type each digit separately.

This is also relevant to WCAG 2.2 Success Criterion 3.3.8, Accessible Authentication (Minimum). Requiring users to transcribe a verification code without an assisting mechanism can create a cognitive function test. W3C’s guidance specifically addresses split inputs that prevent users from pasting the complete code. Read the WCAG guidance on accessible authentication.

Six separate inputs are not automatically a WCAG failure. A segmented implementation that accepts a complete pasted code and distributes it correctly differs substantially from one that forces manual entry into every field. But, a single input makes that support much easier to provide.

Preserve predictable editing and submission

Standard text inputs already support familiar interactions: moving the caret, selecting text, deleting characters, and replacing a selection. Preserve those behaviors.

Automatically moving focus after every digit can make corrections difficult and interrupt screen reader announcements. Automatically submitting after the last digit can also surprise users, particularly when they are still checking what they entered.

An explicit Verify code button gives users control over submission. It also provides a clear action for keyboard, touch, screen reader, and speech input users.

Make errors useful

A failed verification attempt should produce a visible, specific message with a clear next step.

For a format error: “Enter a 6-digit verification code.”

For a rejected code: “That code could not be verified. Check the code and try again.”

For an expired code: “This code has expired. Request a new code to continue.”

After validation fails, set aria-invalid="true" on the input and associate the error message using aria-describedby. Preserve the reference to any instructions that remain useful:

<input
  id="verification-code"
  name="verification-code"
  type="text"
  inputmode="numeric"
  autocomplete="one-time-code"
  pattern="[0-9]{6}"
  aria-describedby="code-help code-error"
  aria-invalid="true"
  required
>

<p id="code-error">
  That code could not be verified. Check the code and try again.
</p>

When errors appear dynamically, make sure assistive technology users receive the feedback through appropriate focus management or a live region. Associating an error with a field does not, by itself, guarantee an immediate announcement.

Provide a clear recovery path

People may receive a code late, miss the message, or need more time to enter it. Provide an easy-to-find Send a new code control and explain relevant expiration rules. After a resend, show an accessible confirmation. If requesting a new code invalidates the previous one, tell the user. Avoid announcing a countdown every second; repeated announcements can interfere with completing the form.

Test the complete interaction

Reviewing the markup is only the beginning. Test whether users can:

  • Reach the input and submit button using a keyboard.
  • Hear an understandable label and instructions with a screen reader.
  • Paste a complete code, including one beginning with zero.
  • Select, replace, and correct entered characters.
  • Use code autofill on supported devices.
  • Understand validation errors and request a replacement code.

The goal is a verification step that people can complete with the tools and interaction methods they already use. One well-labeled input, predictable behavior, and clear feedback provide a dependable foundation.

Related Blog Posts