[BYTE] Effective HTML Forms.

I Find Karma (adam@cs.caltech.edu)
Thu, 4 Jun 1998 02:33:24 -0700


Since we at FoRK appreciate good design, and since we've been thinking a
lot about forms lately, I recommend the Byte article on effective HTML
forms, a Web structure often used inappropriately.

Roy Tennant in Current Cites gives a better recommendation than me:

Udell, who doubles as the BYTE Web manager, not only targets the
markup with comments like "Mark required elements" and "Use layout
and visual cues to organize elements" (he gives examples), but also
the programs that will process the input: "Accept all unambiguous
inputs" (for example, (XXX) XXX-XXX or XXX-XXX-XXXX for phone
numbers) and "Use short error messages linked to longer explanations."

Rohit might appreciate the "future directions" section:

> We've made a lot of progress this time around, but there's still plenty
> of room for improvement. The data dictionary remains just a good idea;
> we haven't rigorously decomposed all our forms to create an inventory of
> reusable widgets.
>
> Another tantalizing possibility is namespace completion. Using the
> replaceable-widget technique shown in the figure , I've prototyped a
> mechanism that accepts partial input in a sidebar and then returns a
> version of the form that swaps in a listbox containing matches resulting
> from a database lookup. This magical effect is the holy grail of
> Web-based data-collection applications. Many commercial toolkits can
> deliver this capability, but homegrown (and, thus, maximally
> customizable) implementations are well within the reach of competent
> scripters.
>
> There's nothing Perl-specific about the techniques discussed here;
> they'll work in any scripting environment. You just need to know how
> HTML forms work and be willing to fluidly adjust the relationship
> between scripts and forms.

The full article is included below and snarfed from

http://www.byte.com/art/9805/sec7/art1.htm

Effective HTML Forms
An overhaul of The BYTE Site prompts us to rethink our methods
of creating and processing forms.
by Jon Udell, May 1998

Web applications nowadays can use all sorts of fancy user-interface
gadgetry, including JavaScript, Java, and Dynamic HTML. Is there still a
place for plain old HTML-based forms? You bet. HTML forms tied to
server-side processing still work just fine. And, as I'll discuss this
month, there are lots of ways to extend and refine the HTML/CGI
technique.

A recent overhaul of our Web site gave me the opportunity to review and
upgrade our forms and related scripts. This effort led m e to articulate
10 principles for effective use of HTML forms.

1. Mark required elements. Many sites do this, but many more don't.
Remember that people are always in a hurry and will bail out of your
application in a heartbeat if it starts to feel like a waste of time.

2. Attach explanations directly to form elements. Put field-level
documentation right on the form, next to or below the widget it
explains. A separate help file is fine, and a hyperlink that jumps
context-sensitively from the form to the relevant part of the help file
is even better. But where practical, it's best to put the explanation
right on the form. Remember: People are in a hurry. If you require
six-character alphanumeric passwords, say so. Don't make users click on
Submit to find out the hard way.

3. Solicit feedback. Add a <textarea> widget that invites users to ask
questions and make comments. Then accumulate that information into a
Web, mail, or news archiv e that you can review periodically. A mailto:
link is fine, too, but it's one click removed from the form. People are
in a hurry, and the Web relentlessly encourages context-switching.

Over time, patterns emerge from these responses. Pay attention to them,
and refine your feedback mechanism accordingly. To improve a business
process, you have to be able to measure it. If you instrument them
properly, Web-based customer-service forms can provide the raw data.

4. Use layout and visual cues to organize elements. Two years ago, I
avoided using HTML tables because a lot of browsers handled them poorly
or not at all. This time around, I formatted all our forms using tables.
The new batch look nicer than the old ASCII-formatted forms, but my
motivation was only partly aesthetic. Built on a grid, forms can best
express the sequences and hierarchies implicit in the data they capture.

The structure that emerged from several rewrites of our current batch of
forms i s a two-column grid of name-value pairs. This design flexibly
accommodates not only simple elements but also more complex clusters of
elements.

Table formatting works in several ways here. The horizontal alignment of
the radio buttons, located in successive rows of the nested table, binds
them into a unit. The adjacency of the cells containing the credit-card
radio button and its four associated widgets binds all these into
another unit. Finally, a background color groups the credit-card
widgets. This design (I hope) wordlessly conveys the following
instructions: 1) Choose credit-card or bill-me-later; 2) if you choose
credit-card, you must fill in the associ-ated fields; and 3) if you fill
in any of these fields, complete them all.

5. Develop a consistent style. The BYTE Site is a cluster of servers
that delivers a suite of applications. We took pains to standardize the
look of the HTML pages dished out by the various applications, such as
archive articles, search r esults, and conference messages. But we
failed to standardize the look and feel of the forms presented by these
applications.

It makes sense to do so, and we will, for reasons that are as much
functional as aesthetic. One instance of the design illustrated in the
screen might work well enough, but it works better when users encounter
consistent variations on the theme.

Given such standardization, you can create and leverage a data
dictionary of form elements, along with associated error-handling code
and messages. For example, we collect e-mail addresses on four different
forms. Clearly, each ought to inherit a common widget, along with
associated error-handling code.

6. Parse forms completely and report all errors and omissions. In order
to download the JDK 1.2 beta from JavaSoft's site, I had to register. On
my first try, the server rejected my form with the "Username cannot
match password" message. So I backed up, corrected that, and rese nt the
form. It rejected my form again, this time with "Required address field
is blank."

This all-too-common behavior irks me. The application saw all the fields
I sent, and didn't send, on the first try. Why not do all the necessary
griping immediately? I'd rather take care of everything at once. Finding
multiple errors one at a time, by bouncing repeatedly off a server,
rapidly erodes my patience.

To spare users this headache, I've settled on an error-handling
technique based on the assumption that it's better to deliver all the
form-processing results all the time. I've implemented the technique in
Perl, but you could just as easily do it in any other Web scripting
language.

It's nothing fancy. I just accumulate the complete list of errors each
time I process the form. If the list isn't empty at the conclusion of
the script's error-checking phase, the script passes the list to a
common library routine that displays all the errors, along with
associated explanations.

An unexpected benefit of this approach was that it greatly accelerated
the process of testing the error-checking code associated with our
forms. In a single cycle, you can verify that a form's handler correctly
reports an incorrectly confirmed password, an empty address field, and
an ill-formed account number.

7. Accept all unambiguous inputs. When I last renewed a digital
certificate on the VeriSign site, the server rejected my order form with
an "Invalid credit card number" message. Why? I'd typed the number with
hyphens, but the application was looking for unhyphenated input. That's
just silly. Here's the line of Perl that will reduce a mixture of 16
digits, hyphens, spaces, or other junk to just 16 digits:

$num=~ s/\D*//g;

C'mon, VeriSign. You said that better service was the reason you raised
your rates on digital certificates. Doesn't my extra hundred bucks buy
me one line of Perl?

8. Use short error messages linked to longer explan ations. As I worked
through the new batch of forms, I consolidated the error messages into a
dictionary of keyword/value pairs. The keywords are short phrases, such
as "AccountNotActive." The values are longer explanations, such as
"please activate your account first, using the activate link on any
protected page." In my case, the dictionary is implemented as a Perl
hash table, but you can easily achieve the same effect in any scripting
language.

This method works in conjunction with a standard error-message routine
shared by all form-handling scripts. When a script checks the input sent
from a form, it does not report any errors directly. Instead, it builds
a list containing the keywords associated with all errors found. For
example:

if (length ($username) < 4)
{push (@errs,"Name Too Short");}
if ($pw1 ne $pw2)
{push (@errs,"Bad Password");}

Then, if the error list is nonempty, the script sends the list to the
error-message routine, which reports errors along with their associated
explanations:

if ($#errs > 0) {
{errorMsg (@errs)}; exit; }

I like this approach for two reasons. In the source code, the error
keywords bind closely to the tests that trigger them, so the code
becomes self-documenting. The same keywords, appearing on the page
generated by the error-message routine, are more explanatory than
numeric codes would be, yet they are more easily communicated than the
accompanying long explanations. And, of course, since the error-message
routine is always prepared to handle a list of keywords, the system
obeys principle 6: It always reports all errors and omissions.

9. Use forms as components. The design of the new subscriber-access part
of BYTE's Web site required the capability to vary the outcome of a
given interaction with a form according to the context in which the form
is invoked. For example, as a subscriber to BYTE magazine, you're
entitled to activate your on-line account and view complete current
articles that are otherwise shown only as abstracts. A link to the
activation form appears on every abstract. Completion of the form leads
back to the full version of the article that was first displayed as an
abstract.

How can you achieve this effect? It's straightforward if you dynamically
generate the form from a template. In this case, the link that invokes
the form self-referentially encodes the URL of the article containing
the link. Here's an example:

<a href="
http://www.byte.com/

perl/activate.pl?mode=form&art
=9802/sec1/art1.htm">
activate</a>.

The signal mode=form tells activate.pl to read and emit the file
activate.htm, which contains the form's HTML. That file contains a
placeholder for a URL to be interpolated into this form:

<input type="hidden" name="art"
value=ART>

Here's how activate.pl renders the form:

if ($mode eq 'form') {
open (F,'activate.htm');
while (
<F>) {
s/value=ART/value=$art/;
print $_; } close F; exit; }

The form's action attribute again names the script activate.pl . But
the form itself contains no element named MODE. So when activate.pl
regains control, it skips the form-generation phase and proceeds to the
form-parsing phase. If there are no errors, it calls a database routine
to activate your account and then issues a confirmation page. A link on
that page invites you to continue reading the article that originally
prompted this sequence of events. The address embedded in that link is
the URL passed on the first call to activate.pl , which was embedded in
the form as a hidden variable during the form-generation phase.

10. Vary widget types according to context. As soon as this problem was
solved, another requirement emerged. BYTE's circulation department
decided to run a circulation drive hosted on another site,
http://www.bytesub.com . We wanted to refer new subscribers from
bytesub.com to the same activation form used by existing magazine
subscribers on The BYTE Site. But the circumstances were different. An
existing BYTE magazine subscriber has to enter a subscriber name and
number on the activation form in order to authenticate. A bytesub.com
subscriber shouldn't have to, because the ordering process on that site
already has this data.

We could tell bytesub.com subscribers to write down their credentials.
Then we could refer them to a byte.com activation form that would
require them to enter that data. But that would be silly. Using a
Web-style remote procedure call (RPC), bytesub.com need only construct
the URLthat transmits this data to activate.pl . It took only a few
tweaks to the template and the script to empower bytesub.com to make a
call like this:

/activate.pl?mode=form&name=
jon&num=123

This causes byte.com to display an activation form with prefilled
subscriber-name and subscriber-number fields.

This was an improvement, but it still wasn't quite right. The name and
number appeared in editable input fields, yet in this context the data
should only be displayed, never changed. Although most users wouldn't
touch this data, it seemed wrong to invite them to do so.

The final iteration resolved this problem by varying the types of the
widgets according to context. As shown in the figure , the template
contains placeholders for two versions of the widget pair. The mode=
signal tells the form generator which pair to include. In a byte.com
context, the form presents empty input boxes. Called from bytesub.com,
it prints the passed values in these same locations.

Future Directions

We've made a lot of progress this time around, but there's still plenty
of room for improvement. The data dictionary remains just a good idea;
we haven't rigorously decomposed all our forms to create an inventory of
reusable widgets.

Another tantalizing possibility is namespace completion. Using the
replaceable-widget technique shown in the figure , I've prototyped a
mechanism that accepts partial input in a sidebar and then returns a
version of the form that swaps in a listbox containing matches resulting
from a database lookup. This magical effect is the holy grail of
Web-based data-collection applications. Many commercial toolkits can
deliver this capability, but homegrown (and, thus, maximally
customizable) implementations are well within the reach of competent
scripters.

There's nothing Perl-specific about the techniques discussed here;
they'll work in any scripting environment. You just need to know how
HTML forms work and be willing to fluidly adjust the relationship
between scripts and forms.

---------------------------------

TOOLWATCH

JHLZip

John Leach
Internet:
http://www.easynet.it/~jhl/apps/zip/zip.html

This handy, free Java application builds an uncompressed zip archive
from a list of class files. Since the JDK's jar utility works only on
entire subtrees, you need something like JHLZip to build a distributable
package from a list of specifically enumerated classes.

---------------------------------

BOOKNOTE

Understanding Digital Signatures
............$34.95

ISBN 0-07-012554-6

A useful survey of the business, legal, and technical issues surrounding
public-key cryptography. It also catalogs vendors of toolkits an d
applications.

-----------------------------------------------------------------

Vary Your Form Widgets According to Context
illustration_link (46 Kbytes) [Image]

-----------------------------------------------------------------

Understanding Digital Signatures
photo_link (50 Kbytes) [Image]

-----------------------------------------------------------------

Principles of Form Design
screen_link (64 Kbytes) [Image]

-----------------------------------------------------------------
Jon Udell is BYTE's executive editor for new media. You can
reach him by sending e-mail to jon.udell@byte.com .

----
adam@cs.caltech.edu

She's addicted to nicotine patches. She's afraid of a light in the
dark.
-- Tori Amos, "Spark"