Why your sign-in form design matters

If people need to sign in to your site, the design of your sign-in form is critical. This is especially true for users on poor connections, on mobile devices, in a hurry, or under stress. Poorly designed sign-in forms get high bounce rates, and each bounce can mean a lost and frustrated user, not just a missed sign-in opportunity. The best practice is to build forms that leverage built-in browser features so they are secure, accessible, and easy to use.

Use the right HTML elements

Use elements built for the job: <form>, <label>, and <button>. These enable built-in browser functionality, improve accessibility, and add semantic meaning to your markup.

Wrap inputs in a <form> element

You might be tempted to wrap inputs in a <div> and handle submission purely with JavaScript. It's generally better to use a plain old <form> element instead. This makes your site accessible to screenreaders and other assistive devices, enables a range of built-in browser features, makes it simpler to build basic functional sign-in for older browsers, and can still work even if JavaScript fails.

Label inputs with <label>

To label an input, use a <label> element.

<label for="email">Email</label>
<input id="email" …>

There are two reasons to do this:

  • A tap or click on a label moves focus to its input. You can associate a label with an input by using the label's for attribute with the input's name or id.
  • Screenreaders announce label text when the label or the label's input gets focus.

Don't use placeholders as input labels. Users are liable to forget what an input was for once they've started entering text, especially if they get distracted. There are many other potential problems with placeholders as well.

It's probably best to put your labels above your inputs. This enables consistent design across mobile and desktop and, according to Google AI research, enables quicker scanning by users. You get full-width labels and inputs, and you don't need to adjust label and input width to fit the label text.

Screenshot showing form input label position on mobile: next to input and above input.
Label and input width is limited when both are on the same line.

Open that demo on a mobile device to see the difference for yourself.

Use <button> for submission

Use <button> for buttons. Button elements provide accessible behaviour and built-in form submission functionality, and they can easily be styled. There's no point in using a <div> or some other element pretending to be a button.

Ensure that the submit button says what it does. Examples include Create account or Sign in, not Submit or Start.

Keep passwords private, but enable users to see them if they want

Password inputs should have type="password" to hide password text and help the browser understand that the input is for passwords. Note that browsers use a variety of techniques to understand input roles and decide whether to offer to save passwords.

You should add a Show password toggle so users can check the text they've entered, and don't forget to add a Forgot password link.

Google sign-in form showing Show password icon.
Password input from the Google sign-in form: with Show password icon and Forgot password link.

Make the most of element attributes

This is where the real power lies. Browsers have multiple helpful built-in features that use input element attributes, and you should leverage them:

  • Use meaningful HTML elements: <form>, <input>, <label>, and <button>.
  • Label each input with a <label>.
  • Use element attributes to access built-in browser features: type, name, autocomplete, required.
  • Give input name and id attributes stable values that don't change between page loads or website deployments.
  • Put sign-in in its own <form> element.
  • Ensure successful form submission.
  • Use autocomplete="new-password" and id="new-password" for the password input in a sign-up form, and for the new password in a reset-password form.
  • Use autocomplete="current-password" and id="current-password" for a sign-in password input.
  • Use aria-label and aria-describedby for password inputs.
  • Don't double-up inputs.
  • Design forms so the mobile keyboard doesn't obscure inputs or buttons.

Ensure successful form submission

Help password managers understand that a form has been submitted. There are two ways to do that:

  • Navigate to a different page.
  • Emulate navigation with History.pushState() or History.replaceState(), and remove the password form from the DOM.

If you're handling submission with an XMLHttpRequest or fetch request, make sure that sign-in success is reported in the response and handled by taking the form out of the DOM as well as indicating success to the user.

Consider disabling the Sign in button once the user has tapped or clicked it. Many users click buttons multiple times, even on fast, responsive sites. That slows down interactions and adds to server load.

Conversely, don't disable form submission awaiting user input. For example, don't disable the Sign in button if users haven't entered their customer PIN. Users may miss something in the form, then try repeatedly tapping the disabled Sign in button and think the form is broken. At the very least, if you must disable form submission while inputs are missing, explain to the user what's missing when they click the disabled button.

Don't force double entry

Some sites force users to enter emails or passwords twice. That might reduce errors for a few users, but it causes extra work for all users and increases abandonment rates. Asking twice also makes no sense where browsers autofill email addresses or suggest strong passwords. It's better to enable users to confirm their email address (you'll need to do that anyway) and make it easy for them to reset their password if necessary.

The broader picture

Good sign-in form design goes beyond the basics outlined here. Be sure to maintain branding and style on your sign-up and sign-in pages, and keep text legible and inputs large enough to work as touch targets on mobile. Test form behavior across browsers and devices, since it varies significantly across platforms. And don't just rely on lab testing: build page analytics, interaction analytics, and user-centric performance measurement into your sign-up and sign-in flow so you can measure real-world impact.

Matching input types to the user's task

The type attribute on an input does more than declare what data you expect. On mobile it also selects which keyboard the browser presents. An <input type="email"> gives users an email-oriented keyboard and triggers the browser's built-in email validation—no JavaScript involvement. For phone-based sign-in, <input type="tel"> pulls up a telephone keypad. The inputmode attribute provides finer control; inputmode="numeric" is well suited to PIN entry.

Keeping the submit control reachable

Mobile keyboards can obscure a sign-in form, and when the submit button ends up hidden behind the keyboard, users may abandon the process entirely. Two mitigations help:

  • Place the email (or phone) field, password field, and sign-in button near the top of the page, with secondary content below.
  • Split the flow across two steps: request the email first, then the password. Amazon and eBay use this pattern, and it reduces the user's cognitive load to one task at a time.
Two screenshots of a sign-in form on an Android phone: one showing how the Submit button is obscured by the phone keyboard.
The Sign in button: now you see it, now you don't.

If you use two steps, keep them inside a single <form> element where possible. Reveal the password input with JavaScript after the email step completes. If a full page navigation between steps is unavoidable, carry the email along in a hidden input on the second page so password managers can associate the credentials correctly.

A sign-in form on an Android phone: the Sign in button is not obscured by the phone keyboard.
The keyboard doesn't obstruct the Sign in button.

Test across the range of devices your audience actually uses and adjust your layout accordingly. BrowserStack offers free testing on real hardware and browsers for open source projects.

Screenshots of a sign-in form on iPhone 7, 8 and 11. On iPhone 7 and 8 the Sign in button is obscured by the phone keyboard, but not on iPhone 11
The Sign in button: obscured on iPhone 7 and 8, but not on iPhone 11.
A sign-in form on the Amazon website: email/phone and password on two separate 'pages'.
Two-stage sign-in: email or phone, then password.

Storing and reusing credentials

Users abandon forms that force them to re-enter data. Browser autofill and password managers can remove that friction, but only when the markup gives them enough context. Two things matter:

  1. Browsers need a stable name or id (not generated per page load), a containing <form>, and a submit button before they will store data for autofill.
  2. The autocomplete attribute tells the browser which stored value belongs in which input.

Use autocomplete="username" on the email field; password managers recognize username across modern browsers even when the input is type="email" and named id="email"/name="email". For password fields, the correct autocomplete value differentiates new passwords from current ones.

New credentials

For a sign-up form or a change-password form's new-password field, apply autocomplete="new-password" and id="new-password".

<input type="password" autocomplete="new-password" id="new-password" …>

Existing credentials

Sign-in forms, and the old-password field in a change-password form, should use autocomplete="current-password" and id="current-password". This signals that the browser should reuse the password it already holds for the site.

<input type="password" autocomplete="current-password" id="current-password" …>

Working with browser password managers

Browser behavior for password storage and suggestion differs by platform, though the goal is common. Safari 11 and later on desktop surfaces its password manager and, when available, offers biometric authentication. Chrome on desktop lists email suggestions and autofills the matching password.

Screenshots of three stages of sign-in process in Safari on desktop: password manager, biometric authentication, autofill.
Sign-in with autocomplete—no text entry required!

The underlying heuristics are not standardized. Firefox, for example, supplements its own guessing with a recipe system. For a deeper treatment of name and autocomplete behavior, the HTML spec's list of 59 possible autocomplete values is the definitive reference.

Screenshots of four stages of sign-in process in Chrome on desktop: email completion, email suggestion, password manager, autofill on selection.
Autocomplete sign-in flow in Chrome 84.

Leaning on built-in strong-password suggestions

Modern browsers decide when to display their password generator UI based on their own heuristics, and this is a feature worth relying on. Safari has offered strong, unique password suggestions since version 12.0.

Firefox password manager on desktop.
Password suggestion flow in Safari.

Built-in generators relieve both users and developers from inventing password rules. Because the browser stores the generated value, users don't need to memorize it. That encourages unique, strong passwords on each site rather than reused ones that propagate when a breach occurs elsewhere.

Enforcing completeness without scripts

The required attribute on both email and password inputs lets the browser handle empty-field prompts and focus management. No JavaScript is needed.

Desktop Firefox and Chrome for Android showing 'Please fill out this field' prompt for missing data.
Prompt and focus for missing data on Firefox for desktop (version 76) and Chrome for Android (version 83).

Sizing controls for actual use

Default browser dimensions for inputs, buttons, and text are too small on desktop and considerably worse on mobile.

Touch targets and spacing

Android accessibility guidance recommends touch targets of 7–10 mm. Apple suggests 48×48 px; the W3C mandates at least 44×44 CSS pixels. Practical padding to reach those sizes is roughly 15 px on mobile inputs and buttons, and around 10 px on desktop. Verify with a real device and a real thumb—try a Lighthouse "tap targets are not sized appropriately" check to catch undersized controls programmatically.

Unstyled form in Chrome for desktop and Chrome for Android.

Thumbs are less precise than forefingers, so don't benchmark touch targets with a stylus or fingertip alone. Adequate margins between inputs also matter; aim for roughly a finger's width of separation. Clear borders do double duty, since default input borders are nearly invisible on some platforms—#ccc or darker on white reads well.

Styled form in Chrome on Android.
Legible text, visible input borders, adequate padding and margins.

Readable text size

Input and button text suffers from the same default sizing problem. A survey of popular sites puts desktop font sizes at 13–16 px, and that physical size should be the floor. The catch: 16 px on Chrome for Android reads very small compared to 16 px on Chrome for desktop. Media queries let you set different pixel sizes per viewport; around 20 px works on mobile, but validate with acquaintances who have low vision. The Lighthouse "document doesn't use legible font sizes" audit can automate the detection of undersized text.

Unstyled form in Chrome on desktop and on Android.
Default styling on desktop and mobile: input text is too small to be legible for many users.

Using browser-native validation feedback

With appropriate type attributes, browsers do basic validation at submit time, display a warning, and move focus to the offending field—no JavaScript.

A sign-in form in Chrome on desktop showing browser prompt and focus for an invalid email value.
Basic built-in validation by the browser.

Beyond the native toast, style invalid fields manually with the :invalid selector. Combine it with :not(:placeholder-shown) so empty inputs don't light up before a user has typed anything.

input[type=email]:not(:placeholder-shown):invalid {
  color: red;
  outline-color: red;
}

JavaScript: when it is required

There is no built-in method for a “Show password” toggle, although work is in progress. Until support lands, the pattern requires JavaScript. A common implementation uses a text button that reveals the entered characters:

<section>
  <label for="password">Password</label>
  <button id="toggle-password" type="button" aria-label="Show password as plain text. Warning: this will display your password on the screen.">Show password</button>
  <input id="password" name="password" type="password" autocomplete="current-password" required>
</section>

Style the button so it reads as plain text rather than a form control:

button#toggle-password {
  background: none;
  border: none;
  cursor: pointer;
  /* Media query isn't shown here. */
  font-size: var(--mobile-font-size);
  font-weight: 300;
  padding: 0;
  /* Display at the top right of the container */
  position: absolute;
  top: 0;
  right: 0;
}

Then wire up the reveal logic:

const passwordInput = document.getElementById('password');
const togglePasswordButton = document.getElementById('toggle-password');

togglePasswordButton.addEventListener('click', togglePassword);

function togglePassword() {
  if (passwordInput.type === 'password') {
    passwordInput.type = 'text';
    togglePasswordButton.textContent = 'Hide password';
    togglePasswordButton.setAttribute('aria-label',
      'Hide password.');
  } else {
    passwordInput.type = 'password';
    togglePasswordButton.textContent = 'Show password';
    togglePasswordButton.setAttribute('aria-label',
      'Show password as plain text. ' +
      'Warning: this will display your password on the screen.');
  }
}
The finished control:
Screenshots of sign-in form with Show password text 'button', in Safari on Mac and on iPhone 7.
Sign-in form with Show password text 'button', in Safari on Mac and iPhone 7.

Accessible password fields

For password rules to be announced to screenreader users, attach aria-describedby to the input, pointing at the element that states the constraints. The screenreader then reads the label, the input type, and the description in sequence:

<input type="password" aria-describedby="password-constraints" …>
<div id="password-constraints">Eight or more characters with a mix of letters, numbers and symbols.</div>

Once “Show password” is present, also add an aria-label warning that the input text will be visible. This prevents a sighted user from inadvertently exposing a password to a shoulder-surfer:

<button id="toggle-password"
        aria-label="Show password as plain text.
                    Warning: this will display your password on the screen.">
  Show password
</button>

WebAIM’s Creating Accessible Forms covers additional accessibility techniques for forms.

Client-side validation timing

Native HTML constraints provide quick checks, but more robust validation needs JavaScript, whether it runs as the user types or at the moment of form submission. The sign-in form codelab’s step 5 demonstrates this with the Constraint Validation API, which is well supported. It lets you add custom validation and still trigger the browser’s native focus and prompt UI.

See Use JavaScript for more complex real-time validation for more detail.

Measuring what matters

Sign‑in forms cannot be improved without data. Discount usability testing helps, but real‑world usage reveals where flows break. Collect:

  • Page analytics — views, bounce rate, and exits on sign‑in and sign‑up pages.
  • Interaction analytics — goal funnels for abandonment points, and events for on‑form actions.
  • Performance metrics — user‑centric metrics set out in the field guide can highlight form slowdowns.

Because those measures point at problems, A/B testing gives a structured way to compare alternatives, and staged rollouts let you verify changes against a user subset before broad release.

UI patterns that aid completion

Most sign-in abandonment is avoidable with careful design. Industry practice centers on a few guidelines:

  • Make the route in obvious: place a clearly labeled Sign In, Create Account, or Register link at the top of the page.
  • Do not decorate the form area with irrelevant offers or content.
  • Defer every request for extra data until the user gets a clear benefit.
  • State the value proposition before the form and give concrete incentives to finish.
  • If practical, offer phone‑number identification instead of email exclusively.
  • Keep “Forgot your password?” prominent; users will occasionally need it.
  • Link directly to the terms of service and privacy policy so users understand data handling before they commit.
  • Match the logo and visual styling of the rest of the site so visitors recognize the destination as legitimately theirs.

Further reading