Web design from Scratch, free online course in design for the webHome - introduction to Web Design from ScratchBasics - effective web design processTutorials - hands-on, practical lessons in designing clear web pagesCase Studies - useful examples that apply the web design principles
Datasheet control

This worked example creates a compact form with multiple similar records, with the familiar appearance of a datasheet.

Features:

  • Familiar datasheet-style input grid
  • Ability to update multiple changed records
  • Shows which fields have been edited

Scenario

You want to let users view, enter, or edit multiple records of the same type. You would like to use the least space possible, without compromising usability.

A conventional way of showing multiple similar rows is the datasheet. It takes the labels for fields and records to the extremes (column and row headers), allowing for a very compact format.

Datasheet example from MS Access Datasheet example from MS Excel

These snippets show examples of the datasheet format from MSAccess and Excel.

1. A basic table

We want to show several data records in a handy grid, let the user sort the list, and delete one or more selected records.

We'll start with a basic table.

ID Name Dept Notes

2. Differentiate the column headers in HTML

It's always good practice to make column headers <th> tags inside the table's <thead> section.

ID Name Dept Notes

3. Style the table

The table headers above have the browser's default <th> styling, so don't look very good. We'll fix that by applying a style class to the table.

In HTML, the table is now <table class="datasheet">

table.datasheet {
	width:100%;
}
.datasheet th {
	padding:3px;
	background-color:#ddd;
	border-top:1px solid #eef;
	border-left:1px solid #eef;
	border-right:1px solid #999;
	border-bottom:1px solid #999;
	color:#003;
	font-size:.9em;
	font-weight:bold;
}
.datasheet th {
	text-align:left;
}
.datasheet tr {
	vertical-align:top;
}
.datasheet td {
	padding:0px;
	border-right:1px solid #999;
	border-bottom:1px solid #999;
	background-color:#fff;
	font-size:.9em;
}
.datasheet td input {
	border:0px none;
	padding:2px;
	width:100%;
	height:100%;
	//width:90%;
	//height:90%;
}

The styled table:

ID Name Dept Notes

The table headers now have the grey, bevelled effect we want. The table cells still look untidy, so we'll fix that now.

In a real datasheet, the entire grid cell is the input field, so we want the form inputs in the cells to fill the entire cell. That's achieved with the section:

.datasheet td input {
	border:0px none;
	padding:2px;
	width:100%;
	height:100%;
	//width:90%;
	//height:90%;
}

In English, this applies to "Any form input that is a child of a table cell within an object of class 'datasheet' ".

Also notice the //width:90%; and //height:90%;

This is a fix for IE versions, which can make the elements overlap outside their containing cells when set to 100% width/height.

Note: I've used both "border:0px" and "none". This is required to force the input controls' borders to be hidden in all browsers.

The // syntax is a comment for CSS. Any line which begins with two forward-slashes should be ignored by browsers. IE fails to ignore this kind of comment, which gives us a handy mechanism for adding special CSS rules for IE only.

(You can also comment out one or more lines of CSS using /* This syntax */ ... which works in practically browsers)

5. Make the datasheet fit into the background

Currently, the table doesn't stand out from the grey background quite enough. We'll use a bit of CSS to give it a groove effect.

To do this, I'll wrap the whole datasheet inside two divs:

.form_groove_outer {
	padding:0px;
	margin:0px;
	border-top:1px solid #669;
	border-bottom:1px solid #fff;
	// border-right:1px solid #fff;
}
.form_groove_inner {
	padding:0px;
	margin:0px;
	border-left:1px solid #669;
	border-right:1px solid #fff;
	// border-right:none;
}

You can simply wrap an element in a div with a solid border, with light right & bottom edges and darker top & left edges, but this technique works better at the corners in Mozilla/Netscape.

Example:

I am in a div with a solid border. I work fine in IE.
I am nested in 2 different divs. I work fine in IE and Mozilla too.

Note: In the CSS above, I'm using the IE trick again. This is because IE works fine when the right-border is defined in the outer groove div, but that makes the top-right corner fit wrong in Mozilla.

Here's our datasheet with the groove effect - nice!

ID Name Dept Notes

6. Add row counters

With a large table, you might want to have row counters. These aren't part of the editable datasheet, so we want to style them the same as table headers.

This is easy to do in HTML/CSS. All we'll do is add <th> cells at the beginning of each line (which is legal).

.datasheet th {
	padding:3px;
	background-color:#ddd;
	border-top:1px solid #eef;
	border-left:1px solid #eef;
	border-right:1px solid #999;
	border-bottom:1px solid #999;
	color:#003;
	font-size:.9em;
	font-weight:bold;
	text-align:left;
}
.datasheet tr th {
	text-align:right;
	padding:1px 3px 1px 1px;
	color:#222;
}

I've added an extra bit of formatting to make the row numbers right-align, and pad them out from the right side of the cells.

You could use this style for any piece of non-editable data, typically a record's unique identifier.

Result:

# ID Name Dept Notes
1
2
3
4
5

7. Final touch - showing changed fields

Often when I use this type of control, when you've edited data and hit submit, the same page reloads. This creates a usability issue: How do you know that your data has indeed been submitted?

There needs to be some visual indicator that a) You've changed a field, and b) That your changes have been submitted and reloaded successfully.

To do that, I use a new CSS ID definition, 'changed', and a little bit of JavaScript:

Important CSS tech note
In CSS, the properties inherited by virtue of an object's ID always have priority over an object's class.

IDs are identified in your style definition with the hash character, whereas classes are preceded with a period/dot.

Because I'm using the ID 'changed' here, I can be sure that it will override any other CSS settings I'm using.

The only properties that take precedence over ID's properties are inline styles written into the HTML, e.g. style="background-color:#f00;".

The CSS:

#changed {
	background-color:#ffa;
}

The HTML & JavaScript:

<input name="record_1_fieldname" value="" type="text"
  onchange="this.id='changed';" />
# ID Name Dept Notes
1
2
3
4
5

Notes on multiple-row forms:

When I use this kind of datasheet in a web application, it's coded so that users can edit multiple records (rows).

Each record has a hidden field, e.g. <input type="hidden" value="" name="record_1_changed" />

When the user changes a field, JavaScript sets the record's 'changed' field to 'True'.

When submitted, the back-end code reads another hidden field ('record_ids') that gives a list of the records present. It then checks the form data to see if each record's 'changed' property is true. Only then does it update the related record in the database.

Top ^ Next topic »
Comments
Great example! I was wanting to do something exactly like this for a new website I'm developing so you've saved me a few days effort. Keep up the good work.  BTW, the page format is a bit knackered - the content part of the page overlaps the grey area on the right.
Adrian G - 10:52 on 20 Aug 2004
Thanks for your feedback Adrian! Please let me know what browser you're viewing in?
Ben Hunt - 12:48 on 20 Aug 2004
I should have said that I'm viewing in IE 5.5 Win.
Adrian G - 01:52 on 20 Aug 2004
I'm viewing in IE5.5/Win now. The code snippets deliberately overlap onto the right-hand column, because they're fixed-font (for speed and clarity), and I didn't want them to wrap round.
Ben Hunt - 02:32 on 20 Aug 2004
It's not just the code snippets. The 'Scenario' content stays within the white content column, but from '1. A basic table' onwards, it *all* overlaps the grey column.Still a great site tho'. :)
Adrian G - 04:12 on 20 Aug 2004
I'm viewing this page now on my home machine and it looks fine.  ie6/xp. Was earlier viewing it in ie5.5 on WinNT.
Adrian G - 07:13 on 20 Aug 2004
Does not work in either Firefox or IE6.
Jørgen T - 10:56 on 21 Aug 2004
Use IDs when there is only one occurrence per page. Use classes when there are one or more occurrences per page. Why not use inline style to be sure to have the highest priority So Doc whats the deal?
Mertz - 03:36 on 29 Aug 2004
Jorgen, what's your platform? I normally use IE6 and Firefox on WinXP, and datasheet works fine..
Ben Hunt - 09:58 on 04 Sep 2004
Mertz, you make valid points. The strength of using ID over inline styles is, of course, it lets you centralise the style definition in one place. I also find writing the ID is easy and works well on multiple browsers.
Ben Hunt - 10:10 on 04 Sep 2004
I have the same problem as Jrgen and am using xp as well.
-elle - 06:07 on 23 Oct 2004
elle, in what way doesn't it work for you? Please could you send me more details, maybe a screenshot? (ben@scratchmedia.co.uk)
Ben Hunt - 11:09 on 25 Oct 2004
Looks fine to me; the yellow divs stretch beyond the content column, but they *all* do and they're *all* the same size. Opera 7.x.
DianeV - 11:14 on 26 Oct 2004
table cell widths and alignment are extremely messed up in Firefox for most of the tables in your examples.
Jao-Quin - 09:40 on 17 Mar 2005
Jao-Quin, please send screenshots to ben@scratchmedia.co.uk with details of OS/Browser. Looks good to me on (IE6 + FFX) x XP
Ben Hunt - 09:49 on 18 Mar 2005
Hey, nice Article!

What about to make the table sortable?
I like this solution: www.kryogenix.org/code/browser/sorttable/
Gregor - 01:41 on 19 Mar 2005
Thanks Gregor. I think that technique would fit well with this design. I'll leave the link in place, rather than reproduce it here.
Ben Hunt - 11:13 on 21 Mar 2005