Steven Pemberton, W3C/CWI
Version date: 2007-02-23
XForms is the new markup language for forms on the Web. This document is a quick introduction to XForms for HTML Forms authors. It shows you how to convert existing forms to their XForms equivalent. It assumes knowledge of HTML Forms, so is not a beginner's tutorial. Although there is mention of additional facilities of XForms beyond those possible in HTML Forms (marked with an asterisk on the headings), it is not a full tutorial on all features of XForms. Part 2 deals with additional features that are not available in HTML Forms.
*Features not present in HTML Forms
Take this simple HTML form:
<html> <head><title>Search</title></head> <body> <form action="http://example.com/search" method="get"> Find <input type="text" name="q"> <input type="submit" value="Go"> </form> </body> </html>
The main difference in XForms is that details of the values collected and
how to submit them are gathered in the head, in an element called
model
; only the form controls are put in the body. So in this
case the minimum you need to put in the head is:
<model> <submission action="http://example.com/search" method="get" id="s"/> </model>
(Elements and attributes in XForms are in lower case.)
The <form>
element is now no longer needed; the
controls in the body look like this:
<input ref="q"><label>Find</label></input> <submit submission="s"><label>Go</label></submit>
What you can hopefully work out from this is that form controls have a
<label>
element as child, the <input>
uses "ref
" instead of "name
", and there is a
separate submit
control that links to the details of the
submission in the head. So the complete example is:
<h:html xmlns:h="http://www.w3.org/1999/xhtml" xmlns="http://www.w3.org/2002/xforms"> <h:head> <h:title>Search</h:title> <model> <submission action="http://example.com/search" method="get" id="s"/> </model> </h:head> <h:body> <h:p> <input ref="q"><label>Find</label></input> <submit submission="s"><label>Go</label></submit> </h:p> </h:body> </h:html>
Another obvious difference is the use of h:
prefixes on the
HTML elements. This has nothing to do with XForms, but with XML which is
designed to allow you to combine different languages together. XForms is
designed to be combined with different languages, not just XHTML. XML
processors need to be told which language different elements belong to,
though one language may be the 'default' language. In the above document,
XForms has been made the default, though XHTML could have been made the
default by changing the xmlns
attributes in the head:
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:f="http://www.w3.org/2002/xforms"> <head> <title>Search</title> <f:model> <f:submission action="http://example.com/search" method="get" id="s"/> </f:model> </head> <body> <p> <f:input ref="q"><f:label>Find</f:label></f:input> <f:submit submission="s"><f:label>Go</f:label></f:submit> </p> </body> </html>
The choice is yours. You can also choose to make neither the default, and
prefix all elements. You can choose any prefix; h:
or
x:
or html:
or form:
, it's up to
you.
In the future, XHTML2 will allow you to write forms without prefixes.
XForms provides equivalents of all HTML Form controls. But there is a
major difference in approach: HTML mainly specifies how the control should
look, while XForms specifies what the control should do. So
while the HTML specification says that the select
element
creates a menu, and the radio
type of input
creates
radio buttons that allow a single choice to be made, XForms has the
select
and select1
elements, which only specify the
intent of the controls, to select zero or more, or only one, element from a
list. How they are presented to the user can vary across devices, or
according to a style sheet. On a mobile telephone where screen space is
scarce, both might be represented with menus, while on a larger screen both
might be represented with selectable buttons. You are allowed to give a hint
to what you want, or you may use a stylesheet to give precise styling, but if
you don't, a device, or a style sheet, may make a choice for you.
So here is how you write the equivalent of the HTML Forms controls.
First name: <input type="text" name="firstname">
is written
<input ref="firstname"><label>First name:</label></input>
There is no need to indicate that it is text: in the absence of any other
information, by default it is text (called string
in XForms).
See later under 'initial values' for how to give any control an initial value.
Message: <textarea name="message" rows="20" cols="80"></textarea>
is written
<textarea ref="message"><label>Message:</label></textarea>
Styling, such as the height and width here, is done using a style sheet. For instance, put this in your style sheet
textarea[ref="message"] { font-family: sans-serif; height: 20em; width: 80em }
Although this mimics the HTML behavior, there is no requirement that you use a sans serif font, nor that you specify the width in rows and columns like this: you could use lengths, or percentages, or whatever:
textarea[ref="message"] { font-family: serif; height: 2cm; width: 20% }
If you want all your textareas to have the same dimensions, you can use
textarea { font-family: sans-serif; height: 20em; width: 80em }
The easiest way to include a style sheet in your document is to add this at the beginning of the document:
<?xml version="1.0"?> <?xml-stylesheet href="style.css" type="text/css"?>
where 'style.css' is the name of your stylesheet.
Radio buttons select one value from a number of alternatives:
Gender: <input type="radio" name="sex" value="M"> Male <input type="radio" name="sex" value="F"> Female
becomes
<select1 ref="sex"> <label>Gender:</label> <item> <label>Male</label><value>M</value> </item> <item> <label>Female</label><value>F</value> </item> </select1>
Bear in mind that this may be presented as any one of radio buttons, a
(scrollable) select area, or a menu. You may include a hint
appearance="full"
on the <select1>
to suggest
that it should be presented as radio buttons. (Use
appearance="compact"
to suggest a select area and
appearance="minimal"
to suggest a menu).
The section on 'initial values' later says how to preselect a value.
Checkboxes select zero or more from a list.
Flavors: <input type="checkbox" name="flavors" value="v"> Vanilla <input type="checkbox" name="flavors" value="s"> Strawberry <input type="checkbox" name="flavors" value="c"> Chocolate
is written
<select ref="flavors" appearance="full"> <label>Flavors:</label> <item> <label>Vanilla</label><value>v</value> </item> <item> <label>Strawberry</label><value>s</value> </item> <item> <label>Chocolate</label><value>c</value> </item> </select>
The section on 'initial values' says how to pre-check values.
Depending on the presence of the multiple
attribute in HTML,
menus select one, or zero or more from a list of options. You either use
<select1>
to select a single choice, or
<select>
to select zero or more.
Month: <select multiple name="spring"> <option value="Mar">March</option> <option value="Apr">April</option> <option>May</option> </select>
would be written:
<select ref="spring" appearance="minimal"> <label>Month:</label> <item><label>March</label><value>Mar</value></item> <item><label>April</label><value>Apr</value></item> <item><label>May</label><value>May</value></item> </select>
If multiple
isn't present on the HTML select
,
then use select1
instead.
The section on 'initial values' says how to preselect values.
<form method="post" enctype="multipart/form-data" ...> ... File: <input type="file" name="attachment">
is written
<submission method="form-data-post" .../> ... <upload ref="attachment"><label>File:</label></upload>
Password: <input type="password" name="pw">
is written
<secret ref="pw"><label>Password:</label></secret>
Ten years of experience with HTML Forms has shown that hardly anyone actually uses reset buttons, and yet very many Web forms include them. A problem is that often the reset button with the text "Reset" is larger than the submission button that is often marked "OK", with the result that people accidently click on reset when they mean to click on OK, sometimes losing a lot of work (few if any browsers offer an undo). Therefore, while it is possible to create a reset button in XForms, it is deliberately harder to do, in order to discourage people unless they really want one:
<input type="reset">
is therefore written
<trigger> <label>Clear all fields</label> <reset ev:event="DOMActivate"/> </trigger>
Buttons have no predefined behavior, but have a behavior attached to them which is triggered when a relevant event occurs.
The button element
<input type="button" value="Show" onclick="show()">
can be written
<trigger><label>Show</label> <h:script ev:event="DOMActivate" type="text/javascript">show()</h:script> </trigger>
or
<trigger ev:event="DOMActivate" ev:handler="#show"> <label>Show</label> </trigger>
where "#show
" locates the element (for instance a
script
element) that implements the behavior:
<script id="show" ...>...
XForms has a number of built in actions that can be executed by a button; see the reset button above for an example.
The fact that the event
attribute has a prefix, means that
you have to add the following XML Namespace to the head:
xmlns:ev="http://www.w3.org/2001/xml-events"
<input type="image" src="..." ...>
is written by putting an image into the <label> element:
<trigger...><label><h:img src="..." .../></label></trigger>
or by specifying it in a stylesheet
<trigger id="activate" ...>
with a stylesheet rule
trigger#activate {background-image: url(button.png); background-repeat: none}
(Likewise for <submit>
.)
Drink: <select name="drink"> <option selected value="none">None</option> <optgroup label="Soft drinks"> <option value="h2o">Water</option> <option value="m">Milk</option> <option value="oj">Juice</option> </optgroup> <optgroup label="Wine and beer"> <option value="rw">Red Wine</option> <option value="ww">White Wine</option> <option value="b">Beer</option> </optgroup> </select>
is written
<select1 ref="drink"> <label>Drink:</label> <item><label>None</label><value>none</value></item> <choices> <label>Soft drinks</label> <item><label>Water</label><value>h2o</value></item> <item><label>Milk</label><value>m</value></item> <item><label>Juice</label><value>oj</value></item> </choices> <choices> <label>Wine and beer</label> <item><label>Red wine</label><value>rw</value></item> <item><label>White wine</label><value>ww</value></item> <item><label>Beer</label><value>b</value></item> </choices> </select1>
<fieldset> <legend>Personal Information</legend> Last Name: <input name="lastname" type="text"> First Name: <input name="firstname" type="text"> Address: <input name="address" type="text"> </fieldset>
is written
<group> <label>Personal Information</label> <input ref="lastname"><label>Last name:</label></input> <input ref="firstname"><label>First name:</label></input> <input ref="address"><label>Address:</label></input> </group>
Note the consistent use of <label>
.
XForms has two controls that are not in HTML, output
and
range
.
The output
control allows you to include values as text in
the document.
Your current total is: <output ref="sum"/>
or
<output ref="sum"><label>Total</label></output>
This can be used to allow the user to preview values being submitted.
You can also calculate values:
Total volume: <output value="height * width * depth"/>
(where height
, width
and depth
are
values collected by other controls.)
This control allows you to specify a constraint on a value.
<range ref="volume" start="1" end="10" step="0.5"/>
A user agent may represent this as a slider or similar.
As you will see in the next section, there is no need for hidden controls in XForms.
The attribute named ref
on each control actually refers to a
child of an instance
element in the model, where the values are
gathered before submission. If there is no instance element there (as in the
search example above), then one is silently created.
Although it is perfectly allowable to let the system create your instance for you, there are reasons why it is a good idea to include one anyway, like this for the search example:
<model> <instance><data xmlns=""><q/></data></instance> <submission action="http://example.com/search" method="get" id="s"/> </model>
From this you immediately see that the only data value submitted is called
"q". The most obvious advantage of this is the documentation value of being
able to see what is being submitted, but the system will now also check that
when you say ref="q"
that there really is a q
in
the instance.
Note that it is essential, for reasons we won't go into detail here, that
you put the xmlns=""
on your instance data, to tell the
processor that the elements here are neither XHTML nor XForms elements.
(Note that we've used the tag <data>
here, but you can
choose any tag you like.)
For initialising controls including initialising checked boxes, and selected menu items etc., you just supply an instance with pre-filled values. For the search example:
<instance><data xmlns=""><q>Keywords</q></data></instance>
would pre-fill the text control with the word Keywords.
Similarly for the example in the checkboxes section, which looks like this:
<select ref="flavors" appearance="full"> <label>Flavors:</label> <item> <label>Vanilla</label><value>v</value> </item> <item> <label>Strawberry</label><value>s</value> </item> <item> <label>Chocolate</label><value>c</value> </item> </select>
You can preselect the vanilla and strawberry checkboxes like this:
<instance><data xmlns=""><flavors>v s</flavors></data></instance>
Similarly for the menus example, which looked like this:
<select ref="spring" appearance="minimal"> <label>Month:</label> <item><label>March</label><value>Mar</value></item> <item><label>April</label><value>Apr</value></item> <item><label>May</label><value>May</value></item> </select>
You can preselect March
and April
like this:
<instance><data xmlns=""><spring>Mar Apr</spring></data></instance>
And for the optgroup
example:
<select1 ref="drink"> <label>Drink:</label> <item><label>None</label><value>none</value></item> <choices> <label>Soft drinks</label> <item><label>Water</label><value>h2o</value></item> <item><label>Milk</label><value>m</value></item> <item><label>Juice</label><value>oj</value></item> </choices> <choices> <label>Wine and beer</label> <item><label>Red wine</label><value>rw</value></item> <item><label>White wine</label><value>ww</value></item> <item><label>Beer</label><value>b</value></item> </choices> </select1>
Preselect the value none
like this:
<instance><data xmlns=""><drink>none</drink></data></instance>
The reason that XForms does not need hidden controls is that any values in
the instance that haven't been bound to by a control are by definition not
visible to the user. So if we want to add a hidden value results
to the search form, we change the instance to:
<instance><data xmlns=""><q/><results>10</results></data></instance>
You don't have to specify the initial instance in the document itself, because you can load it from an external resource, like this:
<instance src="http://example.org/forms/templates/t21.xml"/>
and the document t21.xml can then contain your data, like
<data><w>640</w><h>480</h><d>8</d></data>
(You don't need the xmlns=""
in external instances, though it
doesn't do any harm either.)
Loading external instances gives you immense power. This is because the
ref
attribute on the forms controls doesn't just let you select
an identifier as HTML's name
does, but in fact can be any XPath
expression. XPath lets you select any element or attribute in an XML
document.
This means that once you have learnt XPath, you can bring in any
XML document as instance, even an XHTML document, bind controls to it, and
submit it. For instance to bind to the <title>
element in
an XHTML document, you can use
<input ref="/h:html/h:head/h:title">...
(i.e. the title
element within the head
element
within the html
element, all in the XHTML namespace), or
<input ref="/h:html/h:body/@class">...
which is the class
attribute on the body
element.
For example, suppose a shop has very unpredictable opening hours (perhaps it depends on the weather), and they want to have a Web page that people can go to to see if it is open. Suppose the page in question has a single paragraph in the body:
<p>The shop is <strong>closed</strong> today.</p>
Well, rather than teaching the shop staff how to write HTML to update this, we can make a simple form to edit the page instead:
<model> <instance src="http://www.example.com/shop/status.xhtml"/> <submission action="http://www.example.com/shop/status.xhtml" method="put" id="change"/> </model ... <select1 ref="/h:html/h:body/h:p/h:strong"> <label>The shop is now:</label> <item><label>Open</label><value>open</value></item> <item><label>Closed</label><value>closed</value></item> </select1> <submit submission="change"><label>OK</label></submit>
Note that for this to work, the page in question that is being changed must be correct XHTML, (and not HTML, since only XHTML is an XML document), and your server must accept the "put" method (not all servers do). However, if the XHTML document in question is in a file on the local machine, then you can get the instance from the file, and write it back with a submit. See below.
HTML only allows you to submit the data to one server, in a single way.
XForms allows you to have different submit controls binding to different submission elements in the head to submit the data to different servers, or in different ways.
For instance, the search example could allow the user to submit the search string to different search engines:
<model> <instance><data xmlns=""><q/></data></instance> <submission action="http://example.com/search" method="get" id="com"/> <submission action="http://example.org/search" method="get" id="org"/> </model>
and then in the body:
<submit submission="org"><label>Search example.org</label></submit> <submit submission="com"><label>Search example.com</label></submit>
Just as with HTML there are a number of ways to submit the data. In HTML
how to submit is expressed in two attributes, method
and
enctype
; in Xforms it is expressed in method
only:
HTML | XForms |
---|---|
method="get" | method="get" |
method="post" enctype="application/x-www-form-urlencoded" |
method="urlencoded-post" |
method="post" enctype="multipart/form-data" |
method="form-data-post" |
There are some new ways of submission; the most interesting are
method="post"
which posts the results as an XML document, and
method="put"
which puts the results as an XML document. An
interesting use of this is something like:
<submission action="file:results.xml" method="put"/>
which saves your results to the local filestore by using the
file:
scheme.
Since, as shown above, you can have more than one submission per form, this means that for a large form, you could have separate 'save to disk' and 'submit' buttons.
The default when values have been submitted is for the result returned by
the server to replace the whole document, just as with HTML. However, there
are other options, specified with the attribute replace
on the
submission
element. The value replace="instance"
replaces only the instance, and replace="none"
leaves the form
document as-is without replacing it.
For instance, for an address-change form for a bank, you can provide two buttons, one to prefill the form with name and address based on the account number, and one to submit the changed results:
<model> <instance><data xmlns=""> <accountnumber/><name/><address/> </data></instance> <submission method="get" action="http://example.com/prefill" id="prefill" replace="instance"/> <submission method="get" action="http://example.com/change" id="change" replace="none"/> </model> ... <input ref="accountnumber"><label>Account Number</label></input> <submit submission="prefill"><label>Find</label></submit> <input ref="name"><label>Name</label></input> <textarea ref="address"><label>Address</label></textarea> <submit submission="change"><label>Submit</label></submit>
The 'find' button will replace the instance with a new instance containing the details of the person with the account number, which you can then change; the 'submit' button will then send the changed instance back, leaving the form as-is in the browser to allow further changes or to input a new account number to prefill.
In HTML you can specify that controls are disabled, or read-only but the only way you can change the property is with scripting.
XForms offers easy ways to control these properties, but has other properties you can specify as well:
Note that in XForms it is the collected value that has the property, not the control, but the property shows up on all controls bound to the value.
These properties use a <bind>
element that goes in the
<model>
. To use bind
, you must have an
explicit <instance>
element.
To disable controls you use the relevant
property. For
instance, to say that the credit card number only needs to be filled in if
the person is paying by credit, you can write:
<model> <instance><data xmlns=""> <amount/><method/><cc/><expires/> </data></instance> <bind nodeset="cc" relevant="../method='credit'"/> <bind nodeset="expires" relevant="../method='credit'"/> </model>
This states that the fields cc
and expires
are
only relevant when method
has the value credit
, and
will therefore be disabled for other values of method
. You have
to say "../method
" rather than just method
, because
in a bind
you are talking about the thing referred to in the
nodeset
(which might be a structured element itself). It is as
if you have done a 'change directory' to that element. If you said just
"method
", it would refer to a child element of cc
or expires
. You can also use absolute addressing, like
/data/method
, which would have the same effect as
../method
in this case.
A browser is free to decide how disabled controls are presented (and it may also allow you to specify in a stylesheet how they should look), but typically they will be grayed out in the normal way.
The controls could be written like this (but note that there is no indication that they may get disabled: that is inherited from the value they refer to):
<select1 ref="method"><label>Method of payment:</label> <item><label>Cash</label><value>cash</value></item> <item><label>Credit card</label><value>credit</value></item> </select1> <input ref="cc"><label>Card number:</label></input> <input ref="expires"><label>Expiry date:</label></input>
If we used a structured instance, we could simplify this:
<model> <instance><data xmlns=""> <amount/><method/> <cc> <number/><expires/> </cc> </data></instance> <bind nodeset="cc" relevant="../method='credit'"/> </model>
and the controls then reference the children of 'cc
':
<input ref="cc/number"><label>Card number:</label></input> <input ref="cc/expires"><label>Expiry date:</label></input>
although grouping can be used to reset the context of the
ref
s:
<group ref="cc"> <input ref="number"><label>Card number:</label></input> <input ref="expires"><label>Expiry date:</label></input> </group>
Similarly to relevant
, you can specify a condition under
which a value is read-only. For instance:
<model> <instance><data xmlns=""> <variant>basic</variant><color>black</color> </data></instance> <bind nodeset="color" readonly="../variant='basic'"/> </model>
This example says that the default value of color
is
black
, and can't be changed if variant
has the
value basic
.
A useful new feature in XForms is the ability to state that a value must be supplied before the form is submitted. The simplest case is just to say that a value is always required. For instance, with the search example:
<model> <instance><data xmlns=""><q/></data></instance> <bind nodeset="q" required="true()"/> <submission .../> </model>
but like the readonly
and relevant
attributes,
you can use any XPath expression to make a value conditionally required:
<bind nodeset="state" required="../country='USA'"/>
which says that the value for state
is required when the
value for country
is "USA
".
It is up to the browser to decide how to tell you that a value is required, but it may also allow you to define it in a stylesheet.
This property allows you to add extra constraints to a value. For instance:
<bind nodeset="year" constraint=". > 1970"/>
constrains the year to be after 1970. Note the XPath use of "." to mean "this value". (">" has to be written as > because of XML rules, but you should be used to that already).
It is possible to indicate that a value in the instance is calculated from other values. For instance:
<bind ref="volume" calculate="../height * ../width * ../depth"/>
When a value is calculated like this, it automatically becomes
readonly
.
There are a number of functions available, including arithmetic, string manipulation, date handling, and conditionals using 'if'.
Another useful new feature is the ability to give a value a type. The browser can then check that the values match the required type.
For instance, if the search example is actually only for searching for numbers (for instance for searching in a bug database), then we only have to add:
<bind nodeset="q" type="xsd:integer"/>
This will prevent the value being submitted unless it is an integer.
(You then need to add
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
to the root
element.)
If you want to collect the URL of someone's homepage, then you can specify
<bind nodeset="homepage" type="xsd:anyURI"/>
You will find that some user agents do special things when they know the data type of a value. For instance, when they know that the value is a date, they pop up a date picker rather than require you to type in the characters of the date.
There are a number of useful built-in types you can use, including:
select
)If you have several binds referring to the same value, you can combine them:
<bind nodeset="q" type="xsd:integer" required="true()"/>
For more than one form in a document, you need one model per form, but
then you need to identify which form each control refers to. You do this with
an id
attribute on each model, and a model
attribute on each control:
<model id="search"> <instance><data xmlns=""><q/></data></instance> <submission id="s" .../> </model> <model id="login"> <instance><data xmlns=""><user/><passwd/></data></instance> <submission id="l" .../> </model> ... <input model="search" ref="q"><label>Find</label></input> <submit submission="s"><label>Go</label></submit> ... <input model="login" ref="user"><label>User name</label></input> <secret model="login" ref="passwd"><label>Password</label></secret> <submit submission="l"><label>Log in</label></submit>
If there is a bind
in the model, you can refer to that from
the control instead of directly to the instance value. This allows you to
change the details of how the instance is structured without having to change
the controls. It also means you don't have to specify which model is
involved:
<model> <instance><data xmlns=""><q/></data></instance> <submission id="s" .../> <bind id="query" nodeset="q" required="true()"/> </model> ... <input bind="query"><label>Find</label></input>
(Note that the bind
attribute is a reference to an
id
on a bind
element; it is not an XPath
expression.)
As mentioned in the introduction, this is not a full tutorial on XForms. Here are the main features not treated here:
These are all treated in detail in part 2.