Forms are important—they're the most common way to get information from our users. But just making wireframes of a form misses a big piece of the picture—what it's like to interact with it. An HTML prototype of a form, on the other hand, can look and behave just like the real thing.
In the first post, I showed you how to lay out a form and align the labels the way you want, using HTML and Foundation.
In the second post, I showed you all the different input types you can use.
In this post, I'll show you how to group your inputs and how to provide help to the user while they're filling out the form.
To make the most of these posts, I strongly encourage you to get your hands dirty. Type in the examples and then check them out in your browser. This gets it into your brain, and your fingers, more effectively than just copying and pasting (or worse, just reading).
Grouping
When you've got more than just a few input fields, it makes sense to organize them into logical groups, which you then separate visually. This makes the form less intimidating—it looks more like several small forms than one long one.
Let's make a shipping details form similar to the one we created in the first post. This time, in addition to the shipping address inputs, we'll add an extra input for the user's email address, and we'll split the phone number and email address out into a separate group.
The most obvious way to do this would be to add a second <fieldset>
with its own legend, and put the phone and email inputs in there.
Let's try it. In the index.html
file of a new Foundation project (see this post to find out how to set that up), add this:
It's OK, but the result looks a bit busy (view larger):
There's just a bit too much to process here. We don't need quite so many visual elements to separate the two groups. We could abandon <fieldset>
s and replace the <legend>
s with headings, but that would be semantically less correct. It would also affect the form's accessibility.
A better approach would be to tweak the CSS a bit to reduce the visual clutter. Let's create a new stylesheet and link it up from index.html
.
So open up a new file in your text editor and add this CSS rule to it:
Call the file form.css
and save it in the css
folder. Then add this line to index.html
:
How's that? (View larger.)
It's certainly cleaner. We could leave it at that. Or we could do some other things to further emphasize the grouping.
For example, we could put a thin horizontal line (<hr/>
) between the groups:
Or we could give each group a background color:
Whatever works for you.
Inline help
Sometimes it's not 100% clear from a field's label what the user is meant to enter in the field. Maybe it's something that is simply too long to explain in a short label, so we need some additional text to help the user out.
A well known example is the credit card security code, which is often labeled as something not very helpful, like "CSC" or "CVV". Even "Security code" may not be obvious to some users. So we need to provide the user with an additional explanation somehow.
There are several different approaches we can use:
-
We can have a big lump of explanatory text at the top of the form. These often get ignored though.
-
We can supplement the label with additional text (usually in a smaller font size) for fields that need it.
-
We can use the
placeholder
attribute to give the user an example of the type of information required and its format. -
We can have some help text that appears automatically when a field (or one of a group of fields) gets focus.
-
We can put an icon next to the label that displays help text when the user clicks on it or hovers over it.
The first one is not usually a good idea, so we won't bother with it. The second one is technically very easy to do, so we'll skip that too. And we've already seen how to use placeholder
.
So let's tackle the last two.
Automatic inline help
Let's say you're designing a form that lets the user order a piece of clothing, a t-shirt, for example. They need to select a size, but you want to direct them to your sizing chart if they're not sure. So for just this one field, we're going to have a piece of help text that appears when the size control gets focus.
This is a bit like what eBay does on the password field on its registration form:
(Actually, in a scenario like ours, it's more likely that the "form" is just a couple of fields on a product page that allow the user to select size, color, and quantity.)
Our "form": page structure
Let's go ahead and build a prototype product page for our t-shirt. We're going to make it look like this:
It's got a title (the name of the shirt) at the top. Under that, there's a nice big photo, with additional photos that you can see by clicking the thumbnails on the left (though we'll fake this part— it's not important here). And to the right of the photo, we've got our form, consisting of inputs for choosing the color, size, and quantity, and an "Add to cart" button.
Only the size selector needs inline help, which we're going to display to the right of the selector. But when do we we want the help to appear? I think it's best if we show it both when the selector gets focus, and when the user moves the pointer in the general vicinity of the selector. That way, it will work well on both touch screens and when you've got a mouse and keyboard.
The first thing we need to do is get our basic page structure set up. We'll start out with an empty Foundation index.html
file (refer back to the instructions in this post for that).
Obviously, in a real design, you're going to have global navigation, a footer, and all kinds of other stuff on the page. But here, we're just prototyping the essentials.
For our title, we need a row <div>
containing one column that takes up the whole of the available width. (Not the whole width of the page, but the usable area in the middle, which by default in Foundation has a maximum width of 1000 pixels, and which gets shrunk down and rearranged responsively for smaller screens).
To achieve this, we give the <div>
containing the heading classes of small-12
and columns
. This means that for screen sizes of small and above (i.e., all screen sizes), we want it to take up the whole of the available with (all twelve of the available twelve columns).
So we need to add this to our index.html
, right after the opening <body>
tag:
Next we need another row <div>
that will contain the rest of the content. Within this, we need three column <div>
s: one for the thumbnails, one for the big photo, and one for the form:
Here, I'm using placehold.it to generate placeholder images, instead of using real images. (They have instructions over there that explain how to size the image, how to change the text, and so on.)
Here, the small-
classes divide up the twelve available columns into three, with widths of one, five, and six columns respectively (for all screen sizes). The <div>
for the form is empty at the moment, so we can't see anything there yet:
Things look a bit scrunched up, so let's add a bit of white space. In the last post, I showed you how to put CSS rules in a separate file and link to it from index.html
. But for the sake of speed, this time, we're going to put the rule in a <style>
block in the page's <head>
. Within the <head>
tags, add this:
This just adds top and bottom margins to the title, and gives all the images a bottom margin.
The actual form
Now for the actual form part of the page. This is also going to need some structure. Because we want to position the inline help to the right of the size selector, what we need to do is divide the form up into four row <div>
s: one for each control and its label, and one for the "Add to cart" button.
Within each row, we'll divide the space up into two equal columns, one for the control, and one for the help (where needed). So let's add this within that third, empty <div>
:
Notice how each row has only one columns <div>
, except the second one. This is where the size selector will go—it's the only one that needs a column to contain the inline help. And the whole thing is enclosed in <form>
tags, because, well, it's a form.
But until we add the actual controls, we can't see if it's right. So let's do that now. Add the <label>
s, <select>
s, <option>
s, the <input>
, and the <button>
so it looks like this:
Nothing here that we haven't seen before. (Except I've explicitly set the value
of the quantity <input>
to 1, a sensible default I think.)
And how does it look? So far, so good:
This looks OK, but the form elements could use a bit of white space between them. So add this rule, again between the <style>
tags in <head>
:
This just adds bottom padding to each row. Now the only thing we need to add is the inline help itself. Oh, and there's the little matter of making it appear and disappear when we want. We'll get to that in a minute.
First let's add the HTML. Inside that empty <div>
(the one right after the size <select>
), add this:
This uses Foundation's panel
and callout
classes to style it, plus some inline styling to make it a bit more compact. (Any bigger, and it'll make the row taller, which means things will jump around when we show and hide it.) It also has an aria-live
attribute so that screen readers will be aware of the content when we make it suddenly appear on the screen.
This is how it looks now:
Now we need to hide it, so we just add display: none;
to the existing style
attribute of the inner <div>
(the one with the panel
and callout
classes), so it looks like this:
Next, we need to show it and hide it. The only way to do this is with JavaScript. This is more like "proper programming", but don't be put off by that—I'll do my best to make it simple and easy to understand.
JavaScript: show help on focus
First, we need somewhere to put our JavaScript code. Normally, you would keep it in a separate file, so you can reuse it in multiple HTML pages. But for simplicity, we'll add it in a <script>
block at the bottom of the page, a bit like what we did with the CSS rules in the <style>
block earlier.
Now, jQuery is included with Foundation, so that's what we'll be using here. All the code we'll be writing will go inside jQuery's $(document).ready()
function. This means that whatever we put inside it will only get run once the page has loaded.
To start with, we'll add some code that shows our inline help <div>
when the size <select>
gets focus. (This happens when the user clicks or tabs to it. Or when they tap on it on a touch device.) So add this <script>
block at the bottom, right before the closing </body>
tag:
Do not be alarmed! This may look a bit intimidating, but if we take it piece by piece, you'll see there's not a lot to it.
The <script>
tags tell the browser that what's inside is Javascript. The $(document).ready()
function, as I explained, tells the browser to run the code inside it only after the page has loaded. The real meat here is what is between the curly braces (i.e., after $(document).ready(function(){
and before });
).
Let's look at the first bit:
$('.field_row input, .field_row select')
This says "Hey, jQuery, find any <input>
or <select>
that is a child of something with a class of field_row
."
jQuery uses the exact same selectors (and ways of combining them) as CSS. So that's one less thing to learn. (I covered the very basics of CSS, among other things, in this post.)
So just like in CSS:
- A period means it's a class name. (So
.field_row
means any element with a class offield_row
.) - A hash (
#
) means it's an element ID. (So#size_selector
means the element with the IDsize_selector
.) - Two selectors separated by a space means the second one must be a child of the first for the selector to apply. (So
div input
means any<input>
that is a child of a<div>
.) - A comma means "or". (So
input, select
means any<input>
or<select>
. - You can combine selectors in other ways. For example,
div.field_row
means a<div>
with a class offield_row
.
OK, on to the next part:
.on('focus', function(){
This says "For whatever we just selected, do something when it gets focus." on()
is what's called a function. A function is just a chunk of code that has a name that you can use to run it (to "call it", in programming terms). (The period means "Call this function on the thing we selected.")
on()
looks out for an event, and does something when that event occurs. In this case, the event is focus
. You can tell on()
to look out for other events too, like click
or mouseover
.
Everything between the last (opening) curly brace after function()
and the closing curly brace here:
});
is the code that actually gets run when on()
detects that one of the selected elements has been given focus. That's this line:
$(this).parent().parent().find('.help').show();
What this says is:
- Take the element that was clicked (
this
). - Find its parent element. (In this case, the parent of the
<input>
or the<select>
is thecolumn <div>
that contains it.) - Find that element's parent. (In this case, that's the
row <div>
containing the<input>
/<select>
.) - Within this element, find any element with a class of
help
. (That's the inline help<div>
.) - Finally, show it.
This technique, where you call one function after another like this, is called chaining. It can save you a lot of work. (The alternative would be to store the element you get in step 2, then (step 3) call parent()
on what you stored, then store that, and so on and so on.)
Phew!
Now if you click on the size <select>
(or tab to it), the inline help magically appears. But it doesn't go away when the <select>
loses focus.
JavaScript: hiding help when the selector loses focus
Luckily, to make this happen, we can just copy our existing code and make a couple of small changes. Copy the three lines of code (the ones that call on()
), add a couple of blank lines below it, then paste them in. Now just change focus
to blur
and show
to hide
. The code you pasted in should now look like this:
If you try it now, you'll see that when the <select>
gets focus, the help appears, and when it loses focus, it disappears again. Great! But it's not enough. Earlier we said we want the help to appear on hover as well. This isn't a problem— a few more lines of code will do it. But where do we want the hover to work?
JavaScript: show help on hover too
Here, our help text contains a link (to a page that doesn't exist, unless you feel like creating it). If the help appears when you hover over the <select>
, when you go to click the link, it will disappear as soon as your pointer leaves the <select>
. Which is not very nice.
We need to make the hover work for the element that contains both the <select>
and the help, that is, the row <div>
.
So let's add some more code within our <script>
block:
This time, the selector is simpler, because we're just targeting the rows (that is, the <div>
s with a class of field_row
). (You may be wondering why I'm using this class, which applies to all four rows, instead of just sticking an ID on the one row that contains the help and use that here. The answer is that this way is more flexible—if I want to add help for another field later, I can just add it to the HTML and it will work, without having to change anything in the JavaScript.)
Instead of on()
after the period, this time we've got a function called hover()
. In contrast to on()
, where we specified one piece of code that was run when the event was detected, here we need two: one that tells jQuery what to do when the hover begins, and one that tells it what to do when it ends. That's why there are two function(){}
s.
The code for hover start goes inside the curly braces in the first function(){}
, while the hover end code goes in those of the second. To make things easier to read, lets split it up onto separate lines, like this:
Now we can just put the code that actually does stuff in those two blank lines. This code is going to be exactly the same as for the focus
and blur
events, except here, we don't need those calls to parent()
to navigate up from the field to the row <div>
, because we're already there. So add the necessary lines to make your code look like this:
If you try it now, you'll see that hovering anywhere in the size row makes the help appear, and when you move away, it disappears. Yes!
Except what happens when the size <select>
has focus, and then you hover and move away? No! The help disappears! That shouldn't happen!
JavaScript: actually, don't hide it when the hover ends, in this one specific case
So, what to do? Well, what we need to do is check if the <select>
has focus before we hide the help (at the end of the hover)—and if it does have focus, we do nothing. For this, we'll use JavaScript's if
construct. This lets us check if something is true, then do something. (And if it's not true, we can either do nothing or do something different.)
So change your code so it looks like this:
What's going on here? The only new thing here is that we've wrapped the line that hides the help in an if
block. The line inside the block only gets executed if the bit in the parentheses after if
is true. Let's take a look at that expression:
!$(this).find('input, select').is(':focus')
Ignore the exclamation point for a moment. this
is the row <div>
. Within this <div>
, we're using find()
to get either the <input>
or the <select>
, and then we use the is()
function (which checks if an element has certain attributes) to check if it has focus.
But this gives us an answer of "true" if the element does have focus. But we want to to hide it only if it doesn't have focus. That's where the exclamation point comes in. It means "not", and simply reverses the result of the expression—true becomes false and false becomes true.
And now it works. (You can see it in action here.)
User-triggered inline help
You'll be relieved to hear that user-triggered inline help is much easier to set up. All we need to do is take the prototype we just created and make a few changes (mostly removing stuff).
Adding an icon
First off, we need to add some kind of icon that the user can click or hover over to bring up the help. There is a set of Foundation icons that you can use just by adding one line to your page's <head>
:
Let's add an "i-in-a-circle" icon to the "Size" label. Find it in your HTML and change it so it looks like this:
The fi-info
class on the <i>
element is how we specify which icon we want. (Other icons get fi-something-else, like fi-heart
for a heart or fi-flag
for a flag.)
The Foundation icons are an icon font. This means that you can style them just like text. You can make them bigger, change their color, add shadows, whatever. For now, we're just making the icon a bit bigger, making sure it lines up with the label, and changing the pointer to a hand so that it looks clickable.
Note that the <i>
can't be inside <label>
because clicking the label gives focus to the <select>
(because of the for
attribute that links the two). If we put the icon inside <label>
, clicking it the same as clicking the label.
Also, we need to set the <label>
's display
to inline-block
(instead of the default of block
) to force the label and the icon to stay on the same line.
New JavaScript for new behavior
Now, how do we want it to behave? If we make it so that the help only appears when you hover over the icon, then we're in the same situation we would have been in if we'd made it appear when you hover on the <select>
—when you go to click on the link in the help, it disappears before you can.
There are a couple of things we can do. We could introduce a delay, so that when the pointer moves away from the icon, the help does not disappear immediately. The other alternative is to make the help appear when you click on the icon, and have some way to dismiss it. Since we've already seen how to make things happen on hover, let's go for the click-triggered help this time.
Within our $(document).ready()
, we can get rid of all the code and replace it with this:
Here, we're targeting the <i>
element with a class of fi-info
(our icon), and we're telling the on()
function to look out for click events on it. When it detects a click, we want it to start at this
(the icon), go up two levels in the page hierarchy (by calling parent()
twice), which takes us to the row <div>
, and then call toggle()
on it.
toggle()
is rather clever. It hides the element if it's visible, and shows it if it's hidden. This means you don't need to keep track of its visibility. So that's less work for us. And it gives us a way to dismiss the help—you just click the icon again (which is nice and symmetrical).
And that's it. (See it for real here.)
Bonus learnings! Or I came for the forms, but stayed for the RWD
If you look at either of the above examples on your phone, you'll see that it's just the same thing, but squished down and misaligned. This is a bit of a shame. Foundation is a responsive front-end framework—we can use it to change the layout on smaller screens to something that makes better use of the available screen space.
Above, we used small-
column classes for everything. This means that the defined layout is used for small, medium, and large screens. All we need to do is change the classes a bit to tell Foundation how the page should be laid out on smaller screens.
Here, we're just going to have two layouts: one for small (phone-sized) screens, and one for medium (tablets) and large (desktop) screens.
In our small layout, what we really want is to just have everything stacked vertically: first the title, then the thumbnails, then the big picture, then the form. We can get this by just changing every small-
class name to medium-
. (What this means is that Foundation does something with the column widths we give it for medium and large screens, and treats it as if we didn't specify any column widths at all on small screens—when you don't specify column widths for elements, Foundation makes them full width and stacks them vertically.)
On smaller screens, that looks like this (code):
That's pretty good, but I think it would look better if the thumbnails were below the big photo instead of above it. Foundation has classes you can add to make this happen.
The way you do it is like this. First, you change the order of the elements so that they appear correctly at small screen sizes. Then you add classes to move them left or right on larger screen sizes.
Let's swap those two <div>
s so they look like this:
Now we need to add push
and pull
classes to move these two columns to the left and right so that they are in the right positions for medium and large screens. Adding a push
class pushes the column to the right, while a pull
class pulls the column to the left.
So we need to add the medium-push-1
class to the <div>
that contains the big photo to push it one place to the right. This will leave the first column free for the thumbnails. Then we add the medium-pull-5
class to the <div>
containing the thumbnails to pull it five places to the left, into the first column. This part of the code should now look like this:
Now if we look at it on a small screen (or shrink down our desktop browser window), we can see that the thumbnails are now below the big photo, just like we wanted (real example here):
And at larger screen sizes, the layout is just the same as before.
Conclusion
We've covered quite a lot of ground in this post. Stay tuned for the next post, where we'll look at responsive enabling and responsive disclosure.
This was originally published on Boxes & Arrows on 22 April 2014.
If you liked this post, you should really check out my upcoming book, Prototyping Forms. Just like this, only more and better!