w3.org

HTML Forms - the Next Generation

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

  • W3C's plans for HTML
  • HTML4 Forms
  • XForms
  • Web Forms 2.0
  • XForms Transitional
  • Next Steps

Brief History of HTML

  • HTML versions:
    • HTML 1.0 in 1990
    • HTML 2.0 in 1994
    • HTML 3.2 in 1996
    • HTML 4.0 in 1997
    • W3C workshop on the future of HTML in 1998
      • Decision to migrate from tag soup to XML (XHTML)
      • Work on forms later spun off into separate WG (XForms)
    • XHTML 1.0 in 2000
    • XHTML 2.0 in 2002 (1st Draft)
    • W3C Workshop on Web Applications and Compound Documents in 2004
      • Rumblings of discontent
      • Formation of WhatWG (not part of W3C)

W3C's plans for HTML

  • XML has been a huge success, but not on the desktop
    • XHTML 1.0 was insufficiently compelling
      • Failure to exploit flexibility of XML for compound documents
  • Demand for renewed work on text/html by browser developers and HTML evangelists
    • Incremental improvements in a number of areas including forms
  • W3C is now planning new work on HTML
    • New HTML working group to incrementally extend HTML4
    • Two equivalent serializations: tag soup and XML
    • Separate XHTML WG to continue work on XHTML2
    • Forms working group for continuing work on XForms
  • Incremental extensions to HTML Forms
    • Developed by Joint Task Force with HTML and Forms WGs

HTML4 Forms

An incomplete summary

  • Hugely important to success of the Web
  • Markup for form fields
    • text, buttons, radio buttons, checkboxes, selection lists, field sets
    • each field may be associated with one or more labels
  • Object Model for scripting
    • One or more named forms: document.forms[n]
    • Each form has collection of named fields: document.forms[0].quantity
    • Arrays of fields with the same name: document.forms[0].quantity[2]
    • Properties: name, type, value, readonly, disabled
    • Events: onchanged, onfocus, onblur, onsubmit
  • Scripting required for client-side validation

XForms

  • Enterprise strength forms
    • Multiple implementations including OpenOffice
    • Popular in corporate and government environments
  • Applies Model-View-Controller Design Pattern
    • Separates Presentation, Logic and Data
    • Abstract UI controls offers device independence
    • Can be used with XBL and SVG for rich graphical controls
    • Requires XML Host language (XHTML or SVG)
    • Form data is XML
    • XPath for integrity constraints on data
  • Hasn't caught on for public websites
    • Perception of steep learning curve
    • Not backwards compatible with HTML Forms
    • Lack of native browser implementations (except for Mozilla)

Web Forms 2.0

  • Increment extensions to HTML4 forms
    • Developed by WhatWG (not W3C)
    • Extended set of data types, e.g. date, time, number, range, email and uri
    • Support for date pickers and sliders
    • Regular expression for constraining value (pattern)
    • Fields can be marked as required
    • Input mode (e.g. kanji)
    • Flag to suppress field autocompletion
    • Output element for values set by scripts
    • Relaxes requirement to nest fields in form element
    • Repeated groups of fields (attributes on TR elements)
  • Implemented natively by Opera
    • Script library for Internet Explorer (partial?)

W3C Forms Task Force

  • Joint membership HTML and Forms working group
    • Diversity of experience will ensure a well thought out proposal and a strong standard
  • Expected to work from the ground up
    • Clarify starting assumptions with respect to use cases
    • Examine the key design choices that follow from these assumptions
    • Define synthesis of ideas, taking current proposals into account
    • No rubber stamp for an existing proposal
  • Starting assumptions
    • Incremental extensions to HTML4 Forms markup and object model
    • Must be capable of being deployed on majority of existing browsers via a compatibility library
    • Should provide real value over current practice

Some Key Choices

  • Declarative treatment vs Scripted event handers (as now)
    • Simple spreadsheet like expressions are much cheaper for web page developers than client-side scripting, and enable automated reasoning over form logic
    • JavaScript vs XPath for expression language
  • Inline or separate description of validation and other features
    • Analogous to style attributes and style sheets
  • Can you define the context in which fields must be filled out, or when a field or group of fields is relevant?
  • Separation between stored and presented values
    • Present numbers with 2 digits after decimal point, but retain greater precision as basis for further calculations
  • Can users override the values of computed fields?
  • Repetition model - syntactic or object model based?

XForms Transitional

  • Started life as an experiment to explore design choices and provide input into standardization process
    • Name has changed from forms lite to XForms Tiny and now XForms Transitional and may end up as HTML Forms as standards work proceeds
    • Cross-browser JavaScript library size 6KBytes compressed
    • Works on >99% of desktop browsers: IE 6/7, Firefox, Opera, Safari, Konqueror etc.
    • Usability tweaks in pipeline for Opera Mobile and NetFront 3.4
  • Adds handful of new attributes plus extensions to object model
    • Spreadsheet-like expressions using JavaScript for syntax
    • Topological sort used for efficient calculation of computed fields
  • Aim for synthesis of existing proposals (work in progress)
    • HTML syntax for aspects of XForms architecture as basis for easing transition to full power of XForms for enterprise strength forms

Field data types

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

  • Date picker generated by script or natively
  • Browser doesn't remember the URI used to load each script
  • This causes problems for relative URIs for images
    • when loading script from different web page locations
    • work around is to use an absolute URI
    • this is bad news for running demo's when offline!
  • Many other possibilities besides date and number
    • time, email, URI, integer, etc.
    • potential security and privacy issues
    • disabling autocomplete on a per field basis
  • Dynamic CSS classes for styling according to field state
    • focus, readonly, invalid, irrelevant, missing
    • works nicely in existing browsers (c.f. new psuedo classes)

Regular Expressions

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!

  • type, pattern, constraint, required, relevant, calculate

Computed Fields

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

  • "x + y" is rewritten as "form.x + form.y" for JavaScript eval()

Min and Max values

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)

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

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

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

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

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

  • Repeating fieldset uses a device independent syntax
    • On desktops, implemented as dynamically generated tables
    • On mobile, view one "row" at a time in vertical layout plus navigation controls
  • repeat-number determines minimum number of rows to display
  • Automatically add new row when last row is no longer empty
  • Script API and UI for adding/deleting/re-ordering rows
  • Note label "for" attribute binds to field "name" if no matching "id"
    • This is used to bind labels to field "columns"
  • Expression execution context defnes "$" as local variable
    • Provides array index for current row
    • Field reference foo is re-written as form.foo[$]
    • Expression preprocessor informed by object model

Initializing Fieldsets

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

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

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

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

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

Travel Expense Claims

User overrides for calculated fields

  • Efficient computation of field values based upon topological sort
  • Detects cyclic dependencies
  • But what if user can override calculated value
  • Expense claim in foreign currency provides use case
    • Payments made in cash at known exchange rate
    • Credit card statments in own currency - exchange range unknown
  • Avoid cyclic dependencies via treatment as separate fields
    • Treat overridden field distinctly from calculated field
  • This isn't yet supported by XForms

Summary of Experimental Extensions

  • Markup
    • New attributes: pattern, constraint, calculate, required, relevant, min, max
    • New values for type attribute, e.g. "date", "time", "number" and "range"
    • Extend <label> "for" attribute to match on field name if no matching id
    • Add name and repeat-number attributes to fieldset element
    • New editable attribute for select element
  • Object Model
    • Add new field properties for pattern, constraint, calculate, required, relevant, min and max, with booleans for invalid and missing
    • Add collection of labels to each field
    • Add collection of fields to each label
    • Include fieldset in each form's collection of named fields
    • Add collection of named fields to each fieldset object
    • Small set of built-in methods for use in expressions, e.g. count and sumover
    • Local variables "form" and "$" for expression execution context

Browser based editing

  • Markup + script + Ajax with pages saved on web server
  • designMode has too many flaws
  • I am developing new cross browser editing library that avoids designMode and execCommand
  • Uses DOM2 Range to locate mouse clicks (emulated on IE)
  • Uses empty span element and CSS to emulate editing caret
  • Toolbar + context pane + wysiwyg pane
    • Context pane provides access to information that isn't visible in wysiwyg pane
    • Focus on helping with tasks not element attributes
  • Beta released expected end of 2007 with application to slides, forms and device independent content

Spreadsheets 2.0

Current spreadsheet tools will be obsoleted by the Web!

  • Spreadsheet formulae based upon row/column names (letter + number)
  • HTML allows for logical names that are easier to deal with
  • Browser based editing will make it easier to create HTML forms than is currently possible with today's Spreadsheets
  • Web based solution integrates cleanly with workflow processes
  • Next version of HTML Forms could submit data as XML
  • Databinding mechanism for easy initialization of form contents
  • API support for dynamic save and load without page reload
  • Calls for participation in the new HTML/Forms/XHTML WGs expected in near future!

Questions?