![Sam Dutton](https://web.dev/images/authors/samdutton.jpg) Sam Dutton [X](https://twitter.com/sw12) [GitHub](https://github.com/samdutton) [Mastodon](https://techhub.social/@samdutton) [Bluesky](https://bsky.app/profile/samdutton.bsky.social) [Homepage](https://samdutton.com)

<br />

Learn how to build a sign-up form that's secure, accessible, and easier to use.
The final form is available in [CodePen](https://codepen.io/web-dot-dev/live/VYvvJpj).

## 1. Use meaningful HTML

Learn how to use form elements to make the most of built-in
browser features.

1. [Create a new Pen](https://codepen.io/pen/).

2. Copy and paste the following code into the HTML Editor.

   ```html
   <form action="#" method="post">
     <h1>Sign up</h1>

     <section>
       <label>Full name</label>
       <input>
     </section>

     <section>
       <label>Email</label>
       <input>
     </section>

     <section>
       <label>Password</label>
       <input>
     </section>

     <button id="sign-up">Sign up</button>
   </form>
   ```
3. Click into the live preview to see the HTML form. There are inputs for name,
   email and password. This form uses only the
   [default browser CSS](https://browserdefaultstyles.com).

<iframe height="300" style="width: 100%;" scrolling="no" src="https://codepen.io/web-dot-dev/embed/jEWzNar?default-tab=html%2Cresult" frameborder="no" loading="lazy" allowtransparency="true" allowfullscreen="true">
</iframe>

Each input is in a section and each has a label. The signup button is, importantly,
a `<button>`. Later in this codelab, you'll learn the
special powers of all these elements.

> [!NOTE]
> **Note:** `<input>` elements don't have closing tags. This is because they have no content within the element, thus they are [void (empty) elements](https://www.w3.org/TR/2011/WD-html-markup-20110113/syntax.html#syntax-elements). A `/` character at the end of a void element is optional.

As yourself the following questions:

- Do the default styles *look* OK? What would you change to make the form look better?
- Do the default styles *work* OK? What problems might be encountered using your form as it is? What about on mobile? What about for screen readers or other [assistive technologies](https://web.dev/learn/accessibility/test-assistive-technology.md.txt)?
- Who are your users, and what devices and browsers are you targeting?

### Test your form

You could acquire a lot of hardware and set up a
[device lab](https://www.smashingmagazine.com/2016/11/worlds-best-open-device-labs/),
but there are cheaper and simpler ways to try out your form on a range of
browsers, platforms, and devices:

- [Use Chrome DevTools Device Mode](https://developer.chrome.com/docs/devtools/device-mode) to simulate mobile devices.
- [Send the URL from your computer to your phone](https://support.google.com/chrome/answer/9430554).
- Use a service such as [BrowserStack](https://www.browserstack.com/open-source) to test on a range of devices and browsers.
- Try out the form using a screen reader tool such as the [ChromeVox](https://chrome.google.com/webstore/detail/chromevox-classic-extensi/kgejglhpjiefppelpmljglcjbhoiplfn) Chrome extension.

> [!WARNING]
> **Warning:** Testing your site on a range of devices and browsers is especially important for forms, because [small problems can cause high bounce rates](https://baymard.com/checkout-usability) and lead users to give up on creating an account or completing a purchase.

Open your CodePen's live view, or visit [our live view](https://codepen.io/web-dot-dev/live/VYvvJpj).
Try out your form on different devices using Chrome DevTools Device Mode.

Now open the form on a phone or other real devices. What differences do you see?

## 2. Add CSS to make the form work better

There's nothing wrong with the HTML so far, but you need to make sure your form
works well on a range of users on mobile and desktop.

In this step, you'll add CSS to make the form easier to use.
[Copy and paste this CSS](https://codepen.io/web-dot-dev/pen/JoGLPMv)
into `css/main.css` file.

Click in the preview to see your styled sign-up form.

Does this CSS work for a variety of browsers and screen sizes?

- Try adjusting `padding`, `margin`, and `font-size` to suit your test devices.
- The CSS is mobile-first. Use [media queries](https://developer.mozilla.org/docs/Learn/CSS/CSS_layout/Media_queries) to apply CSS rules for viewports that are at least `400px` wide, and then again for viewports that are at least `500px` wide. Are these [breakpoints](https://www.browserstack.com/guide/responsive-design-breakpoints) adequate? How should you choose breakpoints for forms?

> [!NOTE]
> **Note:** `Viewport` in this context means the display area available for your page. Mobile phones have a smaller viewport than laptops, and a small browser window on a desktop monitor has a smaller viewport than a maximized browser window.

## 3. Add attributes to help users enter data

Add attributes to your input elements to enable the browser to store and autofill
form field values, and warn of fields with missing or invalid data.

Update your HTML so the form code looks as follows:

```html
<form action="#" method="post">

  <h1>Sign up</h1>

  <section>
    <label for="name">Full name</label>
    <input id="name" name="name" autocomplete="name"
    pattern="[\p{L}\.\- ]+" required>
  </section>

  <section>
    <label for="email">Email</label>
    <input id="email" name="email" autocomplete="username"
    type="email" required>
  </section>

  <section>
    <label for="password">Password</label>
    <input id="password" name="password" autocomplete="new-password"
    type="password" minlength="8" required>
  </section>

  <button id="sign-up">Sign up</button>
</form>
```

The `type` values do a lot of work:

- `type="password"` obscures text as it's entered and enables the browser's [password manager](https://passwords.google.com/) to suggest a strong password.
- `type="email"` provides basic validation and ensures mobile users get an appropriate keyboard.

In the preview, click the **Email** label. What happens? Focus moves to the
email input because the label has a `for` value that matches the email input's
`id`. The other labels and inputs work the same way. Screen readers also
announce label text when the label (or the label's associated input) gets focus.

Try submitting the form with an empty field. The browser won't submit the form,
and it prompts to complete missing data and sets focus. That's because we added
the `require` attribute to all the inputs.

Now try submitting with a password that has less than eight characters. The
browser warns that the password isn't long enough and sets focus on the
password input because of the `minlength="8"` attribute. The same works for
`pattern` (used for the name input) and other
[validation constraints](https://developer.mozilla.org/docs/Web/Guide/HTML/HTML5/Constraint_validation).
The browser does all this automatically, without needing any extra code.

Using the `autocomplete` value `name` for the **Full name** input makes sense,
but what about the other inputs?

- `autocomplete="username"` for the **Email** input means the browser's password manager will store the email address as the 'name' for this user (the username!) to go with the password.
- `autocomplete="new-password"` for **Password** is a hint to the password manager that it should offer to store this value as the password for the current site. You can then use `autocomplete="current-password"` to enable autofill in a sign-in form. Remember, this is a *sign-up form*.

> [!NOTE]
> **Note:** [Sign-in form best practices](https://web.dev/articles/sign-in-form-best-practices.md.txt) has more tips for improving form design, layout, and accessibility.

## 4. Help users enter secure passwords

Did you notice anything wrong with the password input?
There are two issues:

- There's no way to know if there are constraints on the password value.
- You can't see the password to check if you got it right.

Don't make users guess. Update the password section of `index.html` with the
following code:

```html
<section>
  <label for="password">Password</label>
  <button id="toggle-password" type="button"
  aria-label="Show password as plain text. Warning: this displays your password on the screen.">
  Show password</button>
  <input id="password" name="password" type="password" minlength="8"
  autocomplete="new-password" aria-describedby="password-constraints" required>
  <div id="password-constraints">Eight or more characters.</div>
</section>
```

This adds new features to help users enter passwords:

- A button (actually just text) to toggle password display. (The button functionality will be added with JavaScript.)
- An `aria-label` attribute for the password-toggle button.
- An `aria-describedby` attribute for the password input. Screen readers read the label text, the input type (password), and then the description.

To enable the password-toggle button and show users information about password
constraints, [copy the JavaScript](https://codepen.io/web-dot-dev/pen/dPGmbmQ),
and paste it into the JavaScript editor.
<iframe height="300" style="width: 100%;" scrolling="no" title="Codelab: Sign-up form best practices | HTML improved + CSS + JS" src="https://codepen.io/web-dot-dev/embed/dPGmbmQ?default-tab=js%2Cresult" frameborder="no" loading="lazy" allowtransparency="true" allowfullscreen="true">
</iframe>

- Would an [icon](https://material.io/resources/icons/?icon=visibility) work
  better than text to toggle password display? Try
  [Discount Usability Testing](https://www.nngroup.com/articles/discount-usability-20-years/)
  with a small group of friends or colleagues.

- To experience how screen readers work with forms, install the
  [ChromeVox extension](https://chrome.google.com/webstore/detail/chromevox-classic-extensi/kgejglhpjiefppelpmljglcjbhoiplfn)
  and navigate through the form. Could you complete the form using ChromeVox
  only? If not, what would you change?

## Go further

This codelab doesn't cover several important features:

- Checking for compromised passwords. You should never allow passwords that have
  been compromised. You can (and should)
  [use a password-checking service to catch compromised passwords](https://web.dev/articles/sign-up-form-best-practices.md.txt#no-compromised-passwords).

- Link to your Terms of Service and privacy policy documents. Make it clear to
  users how you safeguard their data.

- Update the style and brand of your forms to make sure it matches the rest of
  your site. This helps users feel comfortable that they're in the right place
  when entering names and addresses, and especially when making payments.

- Add [analytics and Real User Monitoring](https://web.dev/articles/payment-and-address-form-best-practices.md.txt#analytics-rum).
  Enable the performance and usability of your form design to be tested and
  monitored for real users.