Form Design Patterns Book Excerpt: A Registration Form

Form Design Patterns Book Excerpt: A Registration Form

About The Author

Adam Silver designs simple, human and inclusive websites. He also wrote a little book called MaintainableCSS.
More about Adam

We’re happy to announce Adam Silver’s new book Form Design Patterns. In this excerpt from the book, Adam takes a look at the foundational qualities of a well-designed form and how to think about them. You can also get the book right away →

Let’s start with a registration form. Most companies want long-term relationships with their users. To do that they need users to sign up. And to do that, they need to give users value in return. Nobody wants to sign up to your service — they just want to access whatever it is you offer, or the promise of a faster experience next time they visit.

Despite the registration form’s basic appearance, there are many things to consider: the primitive elements that make up a form (labels, buttons, and inputs), ways to reduce effort (even on small forms like this), all the way through to form validation.

In choosing such a simple form, we can zoom in on the foundational qualities found in well-designed forms.

How It Might Look

The form is made up of four fields and a submit button. Each field is made up of a control (the input) and its associated label.

Registration form with four fields: first name, last name, email address, and password.
Registration form with four fields: first name, last name, email address, and password.

Here’s the HTML:

Labels are where our discussion begins.

Labels

In Accessibility For Everyone, Laura Kalbag sets out four broad parameters that improve the user experience for everyone:

  • Visual: make it easy to see.
  • Auditory: make it easy to hear.
  • Motor: make it easy to interact with.
  • Cognitive: make it easy to understand.

By looking at labels from each of these standpoints, we can see just how important labels are. Sighted users can read them, visually-impaired users can hear them by using a screen reader, and motor-impaired users can more easily set focus to the field thanks to the larger hit area. That’s because clicking a label sets focus to the associated form element.

The label increases the hit area of the field.
The label increases the hit area of the field.

For these reasons, every control that accepts input should have an auxiliary . Submit buttons don’t accept input, so they don’t need an auxiliary label — the value attribute, which renders the text inside the button, acts as the accessible label.

To connect an input to a label, the input’s id and label’s for attribute should match and be unique to the page. In the case of the email field, the value is “email”:

html
<label for="email">Email addresslabel>
<input id="email">

Failing to include a label means ignoring the needs of many users, including those with physical and cognitive impairments. By focusing on the recognized barriers to people with disabilities, we can make our forms easier and more robust for everyone.

For example, a larger hit area is crucial for motor-impaired users, but is easier to hit for those without impairments too.

Placeholders

The placeholder attribute is intended to store a hint. It gives users extra guidance when filling out a field — particularly useful for fields that have complex rules such as a password field.

As placeholder text is not a real value, it’s grayed out so that it can be differentiated from user-entered values.

The placeholder’s low-contrast, gray text is hard to read.
The placeholder’s low-contrast, gray text is hard to read.

Unlike labels, hints are optional and shouldn’t be used as a matter of course. Just because the placeholder attribute exists doesn’t mean we have to use it. You don’t need a placeholder of “Enter your first name” when the label is “First name” — that’s needless duplication.

The label and placeholder text have similar content, making the placeholder unnecessary.
The label and placeholder text have similar content, making the placeholder unnecessary.

Placeholders are appealing because of their minimal, space-saving aesthetic. This is because placeholder text is placed inside the field. But this is a problematic way to give users a hint.

First, they disappear when the user types. Disappearing text is hard to remember, which can cause errors if, for example, the user forgets to satisfy one of the password rules. Users often mistake placeholder text for a value, causing the field to be skipped, which again would cause errors later on. Gray-on-white text lacks sufficient contrast, making it generally hard-to-read. And to top it off, some browsers don’t support placeholders, some screen readers don’t announce them, and long hint text may get cut off.

The placeholder text is cut off as it’s wider than the text box.
The placeholder text is cut off as it’s wider than the text box.

That’s a lot of problems for what is essentially just text. All content, especially a form hint, shouldn’t be considered as nice to have. So instead of using placeholders, it’s better to position hint text above the control like this:

Hint text placed above the text box instead of placeholder text inside it.
Hint text placed above the text box instead of placeholder text inside it.

The hint is placed within the label and inside a so it can be styled differently. By placing it inside the label it will be read out by screen readers, and further enlarges the hit area.

As with most things in design, this isn’t the only way to achieve this functionality. We could use ARIA attributes to associate the hint with the input:

Must contain 8+ characters with at least 1 number and 1 uppercase letter.

The aria-describedby attribute is used to connect the hint by its id — just like the for attribute for labels, but in reverse. It’s appended to the control’s label and read out after a short pause. In this example, “password [pause] must contain eight plus characters with at least one number and one uppercase letter.”

There are other differences too. First, clicking the hint (a

in this case) won’t focus the control, which reduces the hit area. Second, despite ARIA’s growing support, it’s never going to be as well supported as native elements. In this particular case, Internet Explorer 11 doesn’t support aria-describedby. This is why the first rule of ARIA is not to use ARIA:

“If you can use a native HTML element or attribute with the semantics and behaviour you require already built in, instead of re-purposing an element and adding an ARIA role, state or property to make it accessible, then do so.”

Float Labels

The float label pattern by Matt Smith is a technique that uses the label as a placeholder. The label starts inside the control, but floats above the control as the user types, hence the name. This technique is often lauded for its quirky, minimalist, and space-saving qualities.

The float label pattern. On the left, an unfocused text field shows the label inside; on the right, when the text field receives focus, the label moves above the field.
The float label pattern. On the left, an unfocused text field shows the label inside; on the right, when the text field receives focus, the label moves above the field.

Unfortunately, there are several problems with this approach. First, there is no space for a hint because the label and hint are one and the same. Second, they’re hard to read, due to their poor contrast and small text, as they’re typically designed. (Lower contrast is necessary so that users have a chance to differentiate between a real value and a placeholder.) Third, like placeholders, they may be mistaken for a value and could get cropped.

And float labels don’t actually save space. The label needs space to move into in the first place. Even if they did save space, that’s hardly a good reason to diminish the usability of forms.

“Seems like a lot of effort when you could simply put labels above inputs & get all the benefits/none of the issues.”
Luke Wroblewski on float labels

Quirky and minimalist interfaces don’t make users feel awesome — obvious, inclusive, and robust interfaces do. Artificially reducing the height of forms like this is both uncompelling and problematic.

Instead, you should prioritize making room for an ever-present, readily available label (and hint if necessary) at the start of the design process. This way you won’t have to squeeze content into a small space.

We’ll be discussing several, less artificial techniques to reduce the size of forms shortly.

The Question Protocol

One powerful and natural way to reduce the size of a form is to use a question protocol. It helps ensure you know why you are asking every question or including a form field.

Does the registration form need to collect first name, last name, email address and password? Are there better or alternative ways to ask for this information that simplify the experience?

In all likelihood, you don’t need to ask for the user’s first and last name for them to register. If you need that information later, for whatever reason, ask for it then. By removing these fields, we can halve the size of the form. All without resorting to novel and problematic patterns.

No Password Sign-In

One way to avoid asking users for a password is to use the no password sign-in pattern. It works by making use of the security of email (which already needs a password). Users enter only their email address, and the service sends a special link to their inbox. Following it logs the user into the service immediately.

Medium’s passwordless sign-in screen.
Medium’s passwordless sign-in screen.

Not only does this reduce the size of the form to just one field, but it also saves users having to remember another password. While this simplifies the form in isolation, in other ways it adds some extra complexity for the user.

First, users might be less familiar with this approach, and many people are worried about online security. Second, having to move away from the app to your email account is long-winded, especially for users who know their password, or use a password manager.

It’s not that one technique is always better than the other. It’s that a question protocol urges us to think about this as part of the design process. Otherwise, you’d mindlessly add a password field on the form and be done with it.

Passphrases

Passwords are generally short, hard to remember, and easy to crack. Users often have to create a password of more than eight characters, made up of at least one uppercase and one lowercase letter, and a number. This micro-interaction is hardly ideal.

“Sorry but your password must contain an uppercase letter, a number, a haiku, a gang sign, a hieroglyph, and the blood of a virgin.”
— Anonymous internet meme

Instead of a password, we could ask users for a passphrase. A passphrase is a series of words such as “monkeysinmygarden” (sorry, that’s the first thing that comes to mind). They are generally easier to remember than passwords, and they are more secure owing to their length — passphrases must be at least 16 characters long.

The downside is that passphrases are less commonly used and, therefore, unfamiliar. This may cause anxiety for users who are already worried about online security.

Whether it’s the no password sign-in pattern or passphrases, we should only move away from convention once we’ve conducted thorough and diverse user research. You don’t want to exchange one set of problems for another unknowingly.

Field Styling

The way you style your form components will, at least in part, be determined by your product or company’s brand. Still, label position and focus styles are important considerations.

Label Position

Matteo Penzo’s eye-tracking tests showed that positioning the label above (as opposed to beside) the form control works best.

“Placing a label right over its input field permitted users to capture both elements with a single eye movement.”

But there are other reasons to put the label above the field. On small viewports there’s no room beside the control. And on large viewports, zooming in increases the chance of the text disappearing off screen.

Also, some labels contain a lot of text, which causes it to wrap onto multiple lines, which would disrupt the visual rhythm if placed next to the control.

While you should aim to keep labels terse, it’s not always possible. Using a pattern that accommodates varying content — by positioning labels above the control — is a good strategy.

Look, Size, and Space

Form fields should look like form fields. But what does that mean exactly?

It means that a text box should look like a text box. Empty boxes signify “fill me in” by virtue of being empty, like a coloring-in book. This happens to be part of the reason placeholders are unhelpful. They remove the perceived affordance an empty text box would otherwise provide.

This also means that the empty space should be boxed in (bordered). Removing the border, or having only a bottom border, for example, removes the perceived affordances. A bottom border might at first appear to be a separator. Even if you know you have to fill something in, does the value go above the line or below it?

Spatially, the label should be closest to its form control, not the previous field’s control. Things that appear close together suggest they belong together. Having equal spacing might improve aesthetics, but it would be at the cost of usability.

Finally, the label and the text box itself should be large enough to read and tap. This probably means a font size of at least 16 pixels, and ideally an overall tap target of at least 44px.

Focus Styles

Focus styles are a simpler prospect. By default, browsers put an outline around the element in focus so users, especially those who use a keyboard, know where they are. The problem with the default styling is that it is often faint and hard to see, and somewhat ugly.

While this is the case, don’t be tempted to remove it, because doing so will diminish the user experience greatly for those traversing the screen by keyboard. We can override the default styling to make it clearer and more aesthetically pleasing.

input:focus {
  outline: 4px solid #ffbf47;
}

The Email Field

Despite its simple appearance there are some important details that have gone into the field’s construction which affect the experience.

The email field.
The email field.

As noted earlier, some fields have a hint in addition to the label, which is why the label is inside a child span. The field-label class lets us style it through CSS.

The label itself is “Email address” and uses sentence case. In “Making a case for letter case,” John Saito explains that sentence case (as opposed to title case) is generally easier to read, friendlier, and makes it easier to spot nouns. Whether you heed this advice is up to you, but whatever style you choose, be sure to use it consistently.

The input’s type attribute is set to email, which triggers an email-specific onscreen keyboard on mobile devices. This gives users easy access to the @ and . (dot) symbols which every email address must contain.

Android’s onscreen keyboard for the email field.
Android’s onscreen keyboard for the email field.

People using a non-supporting browser will see a standard text input (). This is a form of progressive enhancement, which is a cornerstone of designing inclusive experiences.

Progressive Enhancement

Progressive enhancement is about users. It just happens to make our lives as designers and developers easier too. Instead of keeping up with a set of browsers and devices (which is impossible!) we can just focus on features.

First and foremost, progressive enhancement is about always giving users a reasonable experience, no matter their browser, device, or quality of connection. When things go wrong — and they will — users won’t suffer in that they can still get things done.

There are a lot of ways an experience can go wrong. Perhaps the style sheet or script fails to load. Maybe everything loads, but the user’s browser doesn’t recognize some HTML, CSS, or JavaScript. Whatever happens, using progressive enhancement when designing experiences stops users having an especially bad time.

It starts with HTML for structure and content. If CSS or JavaScript don’t load, it’s fine because the content is there.

If everything loads OK, perhaps various HTML elements aren’t recognized. For example, some browsers don’t understand . That’s fine, though, because users will get a text box () instead. Users can still enter an email address; they just don’t get an email-specific keyboard on mobile.

Maybe the browser doesn’t understand some fancy CSS, and it will just ignore it. In most cases, this isn’t a problem. Let’s say you have a button with border-radius: 10px. Browsers that don’t recognize this rule will show a button with angled corners. Arguably, the button’s perceived affordance is reduced, but users are left unharmed. In other cases it might be helpful to use feature queries.

Then there is JavaScript, which is more complicated. When the browser tries to parse methods it doesn’t recognize, it will throw a hissy fit. This can cause your other (valid and supported) scripts to fail. If your script doesn’t first check that the methods exist (feature detection) and work (feature testing) before using them, then users may get a broken interface. For example, if a button’s click handler calls a method that’s not recognized, the button won’t work. That’s bad.

That’s how you enhance. But what’s better is not needing an enhancement at all. HTML with a little CSS can give users an excellent experience. It’s the content that counts and you don’t need JavaScript for that. The more you can rely on content (HTML) and style (CSS), the better. I can’t emphasize this enough: so often, the basic experience is the best and most performant one. There’s no point in enhancing something if it doesn’t add value (see inclusive design principle 7).

Of course, there are times when the basic experience isn’t as good as it could be — that’s when it’s time to enhance. But if we follow the approach above, when a piece of CSS or JavaScript isn’t recognized or executed, things will still work.

Progressive enhancement makes us think about what happens when things fail. It allows us to build experiences with resilience baked in. But equally, it makes us think about whether an enhancement is needed at all; and if it is, how best to go about it.

The Password Field

We’re using the same markup as the email field discussed earlier. If you’re using a template language, you’ll be able to create a component that accommodates both types of field. This helps to enforce inclusive design principle 3, be consistent.

The password field using the hint text pattern.
The password field using the hint text pattern.

The password field contains a hint. Without one, users won’t understand the requirements, which is likely to cause an error once they try to proceed.

The type="password" attribute masks the input’s value by replacing what the user types with small black dots. This is a security measure that stops people seeing what you typed if they happen to be close by.

A Password Reveal

Obscuring the value as the user types makes it hard to fix typos. So when one is made, it’s often easier to delete the whole entry and start again. This is frustrating as most users aren’t using a computer with a person looking over their shoulder.

Owing to the increased risk of typos, some registration forms include an additional “Confirm password” field. This is a precautionary measure that requires the user to type the same password twice, doubling the effort and degrading the user experience. Instead, it’s better to let users reveal their password, which speaks to principles 4 and 5, give control and offer choice respectively. This way users can choose to reveal their password when they know nobody is looking, reducing the risk of typos.

Recent versions of Internet Explorer and Microsoft Edge provide this behavior natively. As we’ll be creating our own solution, we should suppress this feature using CSS like this:

input[type=password]::-ms-reveal {
  display: none;
}
The password field with a “Show password” button beside it.
The password field with a “Show password” button beside it.

First, we need to inject a button next to the input. The '); // inject button $(this.input).parent().append(this.button); // listen to the button’s click event this.button.on('click', $.proxy(this, 'onButtonClick')); }; PasswordReveal.prototype.onButtonClick = function(e) { // Toggle input type and button text if(this.input.type === 'password') { this.input.type = 'text'; this.button.text('Hide password'); } else { this.input.type = 'password'; this.button.text('Show password'); } };

JavaScript Syntax and Architectural Notes

As there are many flavors of JavaScript, and different ways in which to architect components, we’re going to walk through the choices used to construct the password reveal component, and all the upcoming components in the book.

First, we’re using a constructor. A constructor is a function conventionally written in upper camel case — PasswordReveal, not passwordReveal. It’s initialized using the new keyword, which lets us use the same code to create several instances of the component:

var passwordReveal1 = new PasswordReveal(document.getElementById('input1'));

var passwordReveal2 = new PasswordReveal(document.getElementById('input2'));

Second, the component’s methods are defined on the prototype — for example, PasswordReveal.prototype.onButtonClick. The prototype is the most performant way to share methods across multiple instances of the same component.

Third, jQuery is being used to create and retrieve elements, and listen to events. While jQuery may not be necessary or preferred, using it means that this book can focus on forms and not on the complexities of cross-browser components.

If you’re a designer who codes a little bit, then jQuery’s ubiquity and low-barrier to entry should be helpful. By the same token, if you prefer not to use jQuery, you’ll have no trouble refactoring the components to suit your preference.

You may have also noticed the use of the $.proxy function. This is jQuery’s implementation of Function.prototype.bind. If we didn’t use this function to listen to events, then the event handler would be called in the element’s context (this). In the example above, this.button would be undefined. But we want this to be the password reveal object instead, so that we can access its properties and methods.

Alternative Interface Options

The password reveal interface we constructed above toggles the button’s label between “Show password” and “Hide password.” Some screen reader users can get confused when the button’s label is changed; once a user encounters a button, they expect that button to persist. Even though the button is persistent, changing the label makes it appear not to be.

If your research shows this to be a problem, you could try two alternative approaches.

First, use a checkbox with a persistent label of “Show password.” The state will be signaled by the checked attribute. Screen reader users will hear “Show password, checkbox, checked” (or similar). Sighted users will see the checkbox tick mark. The problem with this approach is that checkboxes are for inputting data, not controlling the interface. Some users might think their password will be revealed to the system.

Or, second, change the button’s state — not the label. To convey the state to screen reader users, you can switch the aria-pressed attribute between true (pressed) and false (unpressed).

When focusing the button, screen readers will announce, “Show password, toggle button, pressed” (or similar). For sighted users, you can style the button to look pressed or unpressed accordingly using the attribute selector like this:

[aria-pressed="true"] {
  box-shadow: inset 0 0 0 0.15rem #000, inset 0.25em 0.25em 0 #fff;
}

Just be sure that the unpressed and pressed styles are obvious and differentiated, otherwise sighted users may struggle to tell the difference between them.

Microcopy

The label is set to “Choose password” rather than “Password.” The latter is somewhat confusing and could prompt the user to type a password they already possess, which could be a security issue. More subtly, it might suggest the user is already registered, causing users with cognitive impairments to think they are logging in instead.

Where “Password” is ambiguous, “Choose password” provides clarity.

Button Styles

What’s a button? We refer to many different types of components on a web page as a button. In fact, I’ve already covered two different types of button without calling them out. Let’s do that now.

Buttons that submit forms are “submit buttons” and they are coded typically as either or