HTML Forms - the Next Generation

Dave Raggett <dsr@w3.org>

wispy clouds in a blue sky

Google, Mountain View
5th March 2007
http://www.w3.org/2007/03/html-forms/

Outline of today's talk

Brief History of HTML

W3C's plans for HTML

HTML4 Forms

An incomplete summary

XForms

Web Forms 2.0

W3C Forms Task Force

Some Key Choices

XForms Transitional

Field data types

Typed fields

Here is the markup for the above form:

<form name="form1" onsubmit="false">
<fieldset>
<legend>Typed fields</legend>
<label for="f1" title="must be a number">Number</label>
<input id="f1" name="x" type="number"/>
<label for="f2" title="must be a date">Date</label>
<input id="f2" name="y" type="date"/>
</fieldset>
</form>

Note: "datatype" may be used as alternative to "type" to work around Opera's use of fixed enumerations for attribute values, which prevents scripts from accessing unrecognized values.

Data types, images and dynamic classes

Regular Expressions

Patterns

Here is the markup for the above form:

<form name="form2" onsubmit="false">
<fieldset>
<legend>Patterns</legend>
<label for="f1"
title="must resemble 1234-1234-1234">Card number</label>
<input id="f1" name="cardnum" value="1234-1234-1234"
pattern="^\d\d\d\d-\d\d\d\d-\d\d\d\d$"/>
</fieldset>
</form>

Prefer to use same attribute names as XForms for consistency where practical!

Computed Fields

Simple calculation

Here is the markup for the above form:

<form name="form3" onsubmit="false">
<fieldset>
<legend>Simple calculation</legend>
<label for="f1">X</label>
<input id="f1" name="x" type="number"/>
<label for="f2">Y</label>
<input id="f2" name="y" type="number"/>
<label for="f3">X + Y</label>
<input id="f3" name="sum" calculate="x+y" type="number" readonly="readonly"/>
</fieldset>
</form>

Based upon JavaScript expressions with preprocessing for field references

Min and Max values

Typed fields

Here is the markup for the above form:

<form name="form4" onsubmit="false">
<fieldset>
<legend>Typed fields</legend>
<label for="f1"
 title="must be a number between -5 and 5">Number</label>
<input id="f1" name="x" type="number" size="2" min="1" max="5"/>
<label for="f2"
 title="must be a date not earlier than 7 Oct 2006">Date</label>
<input id="f2" name="y" type="date" min="7 Oct 2006"/>
</fieldset>
</form>

Exploits Date object for date calculations (mS since start 1 Jan 1970)

Emulate behavior of spreadsheets with normalized presentation

Range controls (sliders)

Ranges

Here is the markup for the above form:

<form name="form5" onsubmit="false">
<fieldset>
<legend>Typed fields</legend>
<label for="f1"
 title="must be a number between 1 and 5">Number</label>
<input id="f1" name="x" type="range"
 size="2" min="1" max="5" step="1"/>
</fieldset>
</form>

Slider control is used when supported natively, e.g. Opera and Safari

Validation Constraints

Validation expressions

Here is the markup for the above form:

<form name="form6" onsubmit="false">
<fieldset>
<legend>Validation expressions</legend>
<label for="f1" title="must be a number">X</label>
<input id="f1" name="x" type="number"/>
<label for="f2" title="must be a number greater than x">Y</label>
<input id="f2" name="y" type="number" constraint="y > x"/>
</fieldset>
</form>

Constraint uses same JavaScript syntax as calculate attribute.

Can use < > and & directly for text/html, but must be escaped as &lt; &gt; and &amp; for delivery as XML

Determining when Fields must be filled out

Conditionally required field

Here is the markup for the above form:

<form name="form7">
<fieldset>
<legend>Conditionally required field</legend>
<label for="f1" title="optional">X</label>
<input id="f1" name="x" type="text"/>
<label for="f2" title="required if x is filled out">Y</label>
<input id="f2" name="y" type="text" required="x != ''"/>
<button type="submit">Submit</button>
<button type="reset">Reset</button>
</fieldset>
</form>

Required uses same JavaScript syntax as calculate attribute.

"needed" can be used as alternative to "required" to workaround Opera bug.

Relevant Field or Groups of Fields

Relevant fields

Here is the markup for the above form:

<form name="form8" onsubmit="false">
<fieldset>
<legend>Relevant fields</legend>
<label title="try with 5 and then with 3"
for="f1">Number of years at current address?</label>
<input id="f1" name="x" type="number"/><br/>
<label title="Needed if years at current address is less than 4"
for="f2">Number of years at previous address?</label>
<input id="f2" name="y" type="number" relevant="x < 4"/>
</fieldset>
</form>

Relevant uses same JavaScript syntax as calculate attribute.

Repeating Sets of Fields

Repeating groups of fields

Here is the markup for the above form:

<form name="form9">
<fieldset name="lineItem" repeat-number="4">
<legend>Repeating groups of fields</legend>
<label for="item">Product Name</label>
<label for="quantity">Number Purchased</label>
<label for="unitprice">Price Per Unit</label>
<input name="item" type="text" title="product name"/>
<input name="quantity" type="number" title="number purchased"/>
<input name="unitprice" type="number" title="price per unit"/>
</fieldset>

<p><label for="total">Total price</label>
<input name="total" readonly="readonly"
 calculate="sumover(lineItem, quantity*unitprice)"/>
<button type="submit">Submit</button>
<button type="reset">Reset</button></p>
</form>

Fieldsets and Device Independence

Initializing Fieldsets

Repeating groups of fields

Here is the markup for the above form:

<form name="form10">
<fieldset name="lineItem" repeat-number="4">
<legend>Repeating groups of fields</legend>
<label for="item">Product Name</label>
<label for="quantity">Number Purchased</label>
<label for="unitprice">Price Per Unit</label>

<!-- first row -->
<input name="item" type="text" title="product name" value="a"/>
<input name="quantity" type="number" title="number purchased" value="10"/>
<input name="unitprice" type="number" title="price per unit" value="1"/>

<!-- second row -->
<input name="item" type="text" title="product name" value="b"/>
<input name="quantity" type="number" title="number purchased" value="2"/>
<input name="unitprice" type="number" title="price per unit" value="3"/>

<!-- any remaining rows will be generated dynamically so that
 there is always at least the number of rows given by repeat-number -->
</fieldset>

<p><label for="total">Total price</label>
<input name="total" readonly="readonly"
 calculate="sumover(lineItem, quantity*unitprice)"/>
<button type="submit">Submit</button>
<button type="reset">Reset</button></p>
</form>

Radio Buttons

Combining different kinds of fields

Here is the markup for the above form:

<form name="form11">
<fieldset>
<legend>Combining different kinds of fields</legend>
<label for="male">Male</label>
<input id="male" name="gender" type="radio" value="male" checked="checked"/>
<label for="female">Female</label>
<input id="female" name="gender" type="radio" value="female"/>
<label for="married">Married?</label>
<input id="married" name="married" type="checkbox" value="married"/>
<label for="maiden">Maiden name</label>
<input id="maiden" name="maiden" relevant="gender=='female' && married"/>
</fieldset>
</form>

Note that checkboxes evaluate as booleans whilst radio buttons evaluate as strings (value attribute).

Selection Lists

Repeating groups of fields

Here is the markup for the above form:

<form name="form12">
<fieldset name="lineItem" repeat-number="4">
<legend>Repeating groups of fields</legend>
<label for="item">Product Name</label>
<label for="quantity">Number Purchased</label>
<label for="unitprice">Price Per Unit</label>
<select name="item">
<option></option>
<option value="hammer">Hammer</option>
<option value="screwdriver">Screwdriver</option>
<option value="spanner">Spanner</option>
</select>
<input name="quantity" type="number" title="number purchased"/>
<input name="unitprice" type="number" title="price per unit"
calculate="price(item)" readonly="readonly"/>
</fieldset>

<p><label for="total">Total price</label>
<input name="total" readonly="readonly"
 calculate="sumover(lineItem, quantity*unitprice)"/>
<button type="submit">Submit</button>
<button type="reset">Reset</button></p>
</form>

Counting Checkboxes

<input name="total" readonly="readonly"
   calculate="crustPrice(size)+toppingPrice(size)*count(toppings)"/>

Note use of author supplied functions for price data

Create your own pizza!
Size

Crust

Toppings





Here is the markup for the above form:

<form name="form13">
<fieldset>
<legend>Create your own pizza!</legend>
<fieldset class="size">
<legend>Size</legend>
<input id="size12" name="size" type="radio" value="12"/>
<label for="size12">12 inch (6 slices)</label>
<br />
<input id="size14" name="size" type="radio" value="14"/>
<label for="size14">14 inch (8 slices)</label>
<br />
<input id="size18" name="size" type="radio" value="18"/>
<label for="size18">18 inch (12 slices)</label>
</fieldset>
<fieldset class="crust">
<legend>Crust</legend>
<input id="crust1" name="crust" type="radio" value="regular"/>
<label for="crust1">Regular</label>
<br />
<input id="crust2" name="crust" type="radio" value="thin"/>
<label for="crust2">Thin</label>
<br />
<input id="crust3" name="crust" type="radio" value="thick"/>
<label for="crust3">Thick</label>
</fieldset>
<fieldset class="toppings" name="toppings">
<legend>Toppings</legend>
<input id="topping1" name="cheese" type="checkbox" value="cheese"/>
<label for="topping1">Extra cheese</label>
<br />
<input id="topping2" name="peperoni" type="checkbox" value="peperoni"/>
<label for="topping2">Pepperoni</label>
<br/>
<input id="topping3" name="salami" type="checkbox" value="salami"/>
<label for="topping3">Salami</label>
<br />
<input id="topping4" name="sausage" type="checkbox" value="sausage"/>
<label for="topping4">Sausage</label>
<br />
<input id="topping5" name="jalapenos" type="checkbox" value="jalapenos"/>
<label for="topping5">Jalapenos</label>
<br />
<input id="topping6" name="peppers" type="checkbox" value="peppers"/>
<label for="topping6">Bell peppers</label>
<br />
<input id="topping7" name="onions" type="checkbox" value="onions"/>
<label for="topping7">Onions</label>
</fieldset>

<p><span class="right">
<button type="submit">Add to my order</button>
<button type="reset">Reset</button></span>
<label for="total">Total price</label>
<!-- crustPrice and toppingPrice defined by webpage author -->
<input name="total" readonly="readonly"
  calculate="crustPrice(size)+toppingPrice(size)*count(toppings)"/></p>
</fieldset>
</form>

Referring to Fieldset Names

Billing Address




Shipping Address



Here is the markup for the above form:

<form name="form14">
<fieldset class="address" name="billto">
<legend>Billing Address</legend>
<label for="f1">Street</label>
<input id="f1" name="street" value="1280 Buena Vista"/>
<br />
<label for="f2">City</label>
<input id="f2" name="city" value="Palo Alto"/>
<br />
<label for="f3">State</label>
<input id="f3" name="state" value="California"/>
<br />
<label for="f4">Zip code</label>
<input id="f4" name="zipcode"/>
<br />
</fieldset>

<p><input id="f5" name="difship" type="checkbox" value="needed"/>
<label for="f5">Ship to a different address</label>
<br clear="all"/></p>

<fieldset class="address" name="shipto" relevant="difship">
<legend>Shipping Address</legend>
<label for="f6">Street</label>
<input id="f6" name="street" value="46 Main Street"/>
<br />
<label for="f7">City</label>
<input id="f7" name="city" value="Redwood City"/>
<br />
<label for="f8">State</label>
<input id="f8" name="state" value="California"/>
<br />
<label for="f9">Zip code</label>
<input id="f9" name="zipcode"/>
<br />
</fieldset>

<p><label for="f10">Will be shipped to</label>
<input id="f10" name="shipCity" readonly="readonly"
 calculate="difship ? shipto.city : billto.city"/></p>
</form>

Comboboxes

Selection fields you can type into

Here is the markup for the above form:

<form name="form15" onsubmit="false">
<fieldset>
<legend>Selection fields you can type into</legend>
<label for="f1">Favorite fruit</label>
<select name="fruit" id="f1" editable="12">
<option>apples</option>
<option>pears</option>
<option>bananas</option>
<option>pineapple</option>
</select>
</fieldset>
</form>

Use native combobox control when available.

Expense Claim



Expenses incurred in own currency


Travel Expense Claims



Expenses incurred in other currencies


User overrides for calculated fields

Summary of Experimental Extensions

Browser based editing

Spreadsheets 2.0

Current spreadsheet tools will be obsoleted by the Web!

Questions?