8 XForms User Interface

8.1 Conditional Constructs For Dynamic User Interfaces

The XForms User Interface allows the authoring of dynamic user interfaces, i.e., user interfaces that vary based on the current state of the instance data being populated. As an example, portions of a questionnaire pertaining to the user's automobile may become relevant only if the user has answered in the affirmative to the question 'Do you own a car?'. Another use case for such dynamic user interfaces is when the underlying XForms Model contains conditional structures.

8.1.1 switch

Editorial note: Raman  
Please do not attach semantics to the element name to prejudge the design.

This element contains one or more case elements. Each case has an id attribute that is used within event handlers appearing within the form controls to activate or deactivate that portion of the user interface created by the markup contained within that case element.

<switch id="01" default="initial">
  <case id="us">
    <group>
      <caption>Please Specify a US Shipping Address.</caption>
    </group>
  </case>
  <case id="uk">
    <group >
      <caption>Please specify a UK shipping address.</caption>
    </group>
  </case>
  <case id="initial">
    <group >
      ...
    </group>
  </case>
</switch>

The above will result in the portion of the user interface contained within the default case being initially displayed. Next, we define an XForms event handler toggle below for activating and deactivating different portions of this conditional construct.

Example: XML Representation: Action <toggle>
<toggle switch="switchID" case="caseID" />

Attribute switch identifies the switch constructor to be affected.
Attribute case identifies the portion of the switch construct to activate.

In addition to event handler toggle, event handler scroll might be used within construct switch to cycle through the various contained case clauses.

8.2 Repeating Structures

The XForms Model allows the definition of repeating structures such as multiple items being purchased within a purchase order. When defining the XForms Model, such higher-level aggregations are constructed out of basic building blocks; similarly, here we define higher-level user interface constructs that build on the form controls defined previously, that can bind to data structures such as lists and collections.

8.2.1 Design Rationale

The basic XForms form controls defined so far permit populating data instances conforming to Schema simpleTypes. These form controls can be aggregated using group(see 8.4 Layout in XForms) to form higher-level user interface form controls. As an extension to this, the user interface markup for repeating structures only adds encapsulation metadata about the collection being populated, as well as the necessary controls needed for adding, deleting and navigating the items in the repeating structure. Finally, this section also defines relevant portions of the processing model that track the item that is current in a repeat structure..

Element repeat encapsulates the following pieces of metadata:

  • Binding expression specifying the collection to be populated by the contained XForms form controls. This binding expression returns a node-set that represents the collection of items over which this repeat will iterate.

    Issue (nodeset-vs-ref):

    Question: should we call this binding attribute node-set as opposed to ref to highlight that we use the returned node-set rather than the single desired node as in most other usages of the ref attribute? Note that submit and reset also use full node-set processing.

  • Starting index of the first element from the collection to be displayed to the user.

  • Number of elements from the collection to be displayed to the user.

8.2.2 Special Event Handlers For Element repeat

We define XForms-specific event handlers for use within element repeat. These event handlers will appear within element onevent to specify the event handler to trigger when an event is received by the containing event listener. In the examples below, we will assume event dom-click; however, note that this specification does not normatively define the mapping between physical events and specific behaviors.

Construct repeat introduces the notion of a cursor that is maintained by the XForms processing model for each repeating structure. Thus, each repeat has its own a conceptual cursor. Event handlers are provided for querying and updating the position of this cursor; this cursor position in turn is used for determining the behavior of insert and delete. Thus, these event handlers can be thought of as the markup equivalent of the additions to the XForms DOM introduced by construct repeat.

  1. setRepeatCursor for marking an item as being current.

    Example: XML Representation:Action <setRepeatCursor>
    <setRepeatCursor repeat="repeatId" cursor="itemID"/>

    Attribute repeat identifies the repeat constructor whose cursor is to be updated.
    Attribute cursor identifies the cursor position. It should be a binding expression that evaluates to an element of the node set being iterated over by this repeat construct.

  2. getRepeatCursor for accessing position of the repeat cursor.

    Example: XML Representation:Action <getRepeatCursor>
    <getRepeatCursor repeat="repeatId" />

    Attribute repeat identifies the repeat constructor whose cursor position is to be obtained.

  3. scroll for changing item that is current.

    Example: XML Representation:Action <scroll>
    <scroll repeat="repeatId" step="n" />

    Attribute repeat identifies the repeat constructor whose cursor position is to be updated.
    Attribute step is an integer value that specifies the amount by which the list is scrolled. Negative values may be used to scroll the list in the reverse direction.

    Issue (additional-actions):

    We may add special values for scrolling to the top or bottom of the list, as well as other needed actions.

  4. insert for inserting an item at the current cursor position into the repeating structure. This causes the instantiation of the necessary user interface for populating a new entry in the underlying collection. It also updates the instance data by instantiating the necessary nodes.

    Example: XML Representation:Action <insert>
    <insert repeat="repeatId" />

    Attribute repeat identifies the repeat constructor being affected, and defaults to the repeat construct within which this event handler appears.

  5. delete for deleting an item from the repeating structure. This causes the destruction of the necessary user interface for populating the entry at the current cursor position in the underlying collection. It also updates the instance data by destroying the necessary nodes.

    Example: XML Representation:Action <delete>
    <delete repeat="repeatId" />

    Attribute repeat identifies the repeat constructor being affected, and defaults to the repeat construct within which this event handler appears.

The event handlers enumerated above may be used within event listeners attached to button elements placed inside the body of construct repeat. In combination with the facilities provided by element group and CSS layout, this allows document authors to customize the positioning of controls for standard actions such as insert or delete.

8.2.3 repeat

Element repeat represents a repeating homogenous collection, in other words, a collection consisting entirely of like form controls.

<repeat ref="bindingExpr" startIndex="si" number="n">
  <caption>Shopping Cart</caption>
  <!-- XForms UI for one element of the collection -->
  <!-- controls for adding, deleting and navigating entries -->
</repeat>

Notice that the underlying schema for the collection being populated would typically have defined attributes minOccurs and maxOccurs; these values will in turn determine if the user agent displays appropriate UI controls for the user to add or delete entries in the collection. Event listeners within element repeat control UI aspects such as scrolling and insertion. This specification will not specify normative means for displaying such add and delete controls; as with the rest of the XForms User Interface design, we leave these to be flexible while showing a default presentation.

Example: XML Representation: <repeat>
<repeat
  (common attributes)
  startIndex = xsd:positiveInteger : 1
  number = xsd:nonNegativeInteger
>
  <!-- caption, help?, hint?, onevent?, ( any form control )* -->
</repeat>

common attributes defined in 7.13.1 Common Attributes
startIndex = xsd:positiveInteger : 1 - 1-based hint to the XForms Processor as to which starting element from the collection to display.
number = xsd:nonNegativeInteger - hint to the XForms Processor as to how many elements from the collection to display.
any form control - any form control defined in 7 Form Controls

8.2.4 Design Consequences

This subsection enumerates the design consequences and is for members of the Working Group to evaluate the above design.

  • Binding expression is placed on element repeat and should refer to the collection being populated, not to an individual item of the collection. Thus, it would be items/item in a purchase order, where element items contains one or more item children.

  • The form controls appearing inside element repeat needs to be suitable for populating individual items of the collection. Thus, to continue the purchase order example, the contained XForms form controls would need to be suitable for populating a data instance conforming to item.

  • A simple but powerful consequence of the above is that if the XForms Model specifies nested collections, then we can create a corresponding user interface by nesting repeat elements. As an example, consider the XForms Model for a hypothetical purchase order that contains element items for holding collection of item elements. Further, assume that element item comprises of two atomic fields catalogNumber, partNumber and a collection colors which in turn holds one or more color elements. The user interface for populating this data instance would use nested repeat elements.

  • Notice that the contained XForms form controls inside element repeat do not explicitly specify the index of the collection entry being populated. This is intentional; it keeps both authoring as well as the processing model simple. But as a consequence, the user interface cannot bind to an element from the underlying collection out of sequence. Notice that this is not a serious drawback because the use interface layer can always populate a specific member of a collection without using element repeat.

8.3 Reusable Form Controls

8.3.1 Creating User Interface Templates

User Interface templates allow the creation of reusable user interface components. Just as we can define data types and structures that can be reused within the XForms Model, reusable user interface components allow us to design complex user interfaces using the basic building blocks described in the previous section, and then reuse these components in multiple situations. As with any component framework, this has two basic requirements:

  • Components need to declare what aspects of the component are parameterizable by the caller.

  • The caller needs to be able to override the default values of the parameters declared in the component.

Here, we describe such a component framework along with sample markup. For this example, assume that USShippingAddress is a reusable data type that is used in multiple places in the XForms Model, e.g. the user will be asked for a billingAddress and shippingAddress--both of type USShippingAddress.

First, we show a simple example that is designed to bind an XForms form control to a model item of type address with no attention to making the component reusable.

<group>
  <textbox ref="address/street">
    <caption>Please enter your street address</caption>
  </textbox>
  <textbox ref="address/zip">
    <caption>Zip Code</caption>
  </textbox>
</group>

Next, we prepare the above fragment to become a reusable component that could be used for obtaining both the shipping and billing address. To do this, we need to parameterize those portions of the component that the caller will wish to modify.

<uiTemplate id="AddressWidget">
  <param name="streetPrompt"/>
  <param name="zipPrompt"/>
  <param name="border" value="line"/>
  <group border="$border">
    <textbox ref="address/street">
      <caption><value-of name="streetPrompt"/></caption>
    </textbox>
    <textbox ref="address/zip">
      <caption><value-of name="zipPrompt"/></caption>
    </textbox>
  </group>
</uiTemplate>

Note that the markup shown above does not create a user interface; user interface is created by explicitly instantiating the component via element useUITemplate described next.

Next, we use this component to instantiate the user interface for obtaining the shipping and billing address.

<useUITemplate ref="myAddress" component="AddressWidget">
  <withParam name="streetPrompt">Shipping Street Address</withParam>
  <withParam name="zipPrompt">Zip Code for shipping state</withParam>
  <withParam name="border">dotted</withParam>
</useUITemplate>

The reusable component is instantiated by element useUITemplate; parameter values are specified by the contained withParam elements. Attribute xform sets the binding context relative to which binding expressions within the instantiated template get evaluated.

8.3.2 DTD For uiTemplate And useUITemplate

TODO: convert to 'XML Representation' consistent with rest of spec.

<!--       param element for use in uiTemplate -->
<!ELEMENT  param      EMPTY>
<!--       name       Name of parameter being declared           -->
<!ATTLIST  param
  name     CDATA      #REQUIRED>
<!--       Defines a reusable user interface template -->
<!ELEMENT  uiTemplate   (param*, %FormControls;+)>
<!--       id         Unique ID for use when instantiating this template -->
<!ATTLIST  uiTemplate
  id       ID         #REQUIRED>
<!--       Used to pass parameter values when instantiating uiTemplate -->
<!ELEMENT  withParam  #MIXED>
<!--       name       Name of parameter whose value is being specified -->
<!ATTLIST  withParam
name       CDATA      #REQUIRED>

8.4 Layout in XForms

The group element is used as a container for defining a hierarchy of form controls. Groups lay out their children using a constraint-based system that supports both relative flexible sizing and intrinsic sizing. Groups can be nested to create complex hierarchies. Using CSS, an inline box can be specified using the display property with a value of inline. A block-level group can be specified with a value of block, which is the default.

Example: XML Representation: <group>
<group>
  <!-- all form controls & mixed content -->
</group>

All form controls defined so far are treated as inline text for purposes of XHTML processing. XForms visual clients are expected to use a a box layout model as defined by CSS for determining the overall layout of the XForms visual interface. Grouping of form controls using element group also provides semantics about the relationship amongst user interface controls; such knowledge can be useful in delivering a coherent UI to small devices--e.g., if the user interface needs to be split up amongst several screens, controls appearing inside the same group would typically be rendered on the same screen.

Finally, the hierarchy defined by nested group elements is used to determine the traversal order specified by attribute navindex on form controls. Setting the input focus on a group results in the focus being set to the lowest form control in the tabbing order within that group.

Issue (group-binding):

t is an open issue whether the binding attribute xform is allowed on element group. It might make authoring easier but makes implementations significantly harder. Note that this note is here because at one point in our design we said that controls inside a group could use relative XPath expressions with the context being set by the containing group.

8.4.1 Orientation and Direction

Containers typically have an orientation and a direction. The box-orient CSS property specifies the orientation of the group. It has values of horizontal, vertical, or inherit. A horizontal group lays out its children in a horizontal line, and a vertical group stacks its children vertically.

The box-direction CSS property specifies the direction of the group. It has values of normal, reverse, and inherit. A normal horizontal group lays out its children from left to right, and a normal vertical group lays out its children from top to bottom.

Direction within nested groups is inherited by default. If direction is omitted on the outermost group, it is assumed to have a horizontal orientation and normal direction.

<group>
  <textbox  ref="/person/name">
    <caption>Please enter your name</caption>
  </textbox>
  <textbox ref="/person/ssid">
    <caption>Enter your SSID</caption>
  </textbox>
</group>

When items are placed in a group without specifying any additional information about their size, then the sizes the children intrinsically. In other words, the group makes each child only as big as it needs to be. Notice that in the above example, the two form controls are only as big as they need to be, and that this in turn determines the size of the group (since we assume for simplicity that this group is not nested).

Widths can be specified for items inside a horizontal group. When an object specifies its width in CSS, it is telling the group that it would like to be that width. Similarly, heights can be specified in CSS for items in a vertical group. A non-nested group placed inside an enclosing CSS block will obey all the usual sizing rules of the block. For example, setting the width of a non-nested group to 100% ensures that the group is the maximum width permitted by the enclosing CSS block.

8.4.2 Alignment

The box-align property specifies how controls are aligned along the orientation of the group. Its possible values are left, center, right, top, bottom, baseline, stretch and inherit. The default value is stretch.

By default a horizontal group ensures that all children are the same height. Once a height is computed for a horizontal group, all of the children are stretched vertically to the height of the group (minus the CSS border and padding on the group). Similarly, a vertical group ensures that all its children are the same width. The stretch policy overrides any specified width or height values.

<group style="box-orient: vertical">
  <output ref="/person/name"/>
  <output ref="/person/age"/>
  <output ref="/person/country"/>
</group>

In addition to stretch, a horizontal group can also align its children using the values top, center, baseline and bottom. A vertical group can align its children using the values left, center, and right. When these values are used, the items are no longer stretched. They are sized intrinsically and then aligned on the group axis according to the specified property value on the containing group.

8.4.3 Controlling Automatic Sizing

The layout algorithm can be controlled by specifying the degree to which items may flex i.e., the degree to which an item allows itself to be auto-sized. Items in groupes fall into two categories: flexible and inflexible. Inflexible objects will not grow, even when there is extra space left over in the group. When several objects in a group are flexible, the extra space is divided among the objects based on how flexible they are. The group determines how much space to give an object by adding up the flex values on all of its children. An object gets an amount of extra space equal to the percentage of flex that it is responsible for.

For example, if two objects have a flex of 1, then after both objects are given their preferred sizes, the first object gets 1/(1+1) = 1/2 of the extra space, and the second object also gets 1/2 of the extra space.

<group style="box-orient: horizontal; width: 200px">
  <textbox  style="box-flex: 1"  ref="/person/name>
    <caption>Please enter your full name: </caption>
  </textbox>
  <textbox  style="box-flex: 1.5" ref="/person/age>
    <caption>How young?</caption>
  </textbox>
</group>

8.4.4 Preferred, Minimum, and Maximum Sizes

For inflexible objects, the specification of the width and height CSS properties can be used to specify a preferred size. If these properties are omitted, an inflexible object will be sized intrinsically, i.e., it will be given the minimum amount of space required to lay out the item.

With flexible objects, there are more options. Just as with inflexible objects, the width and height properties can be used to specify a preferred size. Unlike inflexible objects, however, this size is only a guideline. A flexible object will stretch as necessary. It will also shrink if required until it can shrink no more (e.g., when the object hits its minimum required intrinsic size).

 <group style="box-orient: vertical">
  <textbox style="box-flex: 1; height:1000px" ref="/person/name">
    <caption>Please enter your name:</caption>
  </textbox>
</group>

In the above example if the group were to shrink, the textbox being flexible would shrink--despite its preferred height of 1000px. The group continues to shrink minimum required height for the textbox is reached. After that, the textbox can shrink no further. If the group were to continue to shrink, the form control's contents would be clipped, and a portion of the control would no longer be visible.

For a more fine-grained control of minimum and maximum sizes, the min-width, min-height, max-width, and max-height CSS properties can be used. When specified, these properties provide extra information to the group as it shrinks and grows the object in question.

In a horizontal group, for example, if a minimum width is specified, then the flexible object will not be allowed to shrink below that width. If a maximum width is specified, then the flexible object will not be allowed to grow beyond that width.

The above example demonstrates the use of min-height and max-height within a vertical group. In the first image the group has been shrunk until it is smaller than 100 pixels in height. Because the iframe has a specified minimum height of 100 pixels, it is not allowed to shrink any further, and so as the group falls below 100 pixels, the iframe gets clipped, and portions of it become invisible.

In the second image, the group has been expanded past 300 pixels in height. Even though the group is getting bigger, the extra space is not being consumed by the iframe, because its maximum height of 300 pixels has been reached. It will grow no further.

Below is another example illustrating min and max width.

Example unavailable at publication time

In the above example, the group has been stretched so that it is very wide. The first child has a maximum width of 50 pixels, and it divides the excess space equally with the second child until its maximum width has been reached. After that, since it is not allowed to grow any further, the remaining space all goes to the second child.

8.4.5 Packing Controls

When all of the items within a group element are inflexible or when all objects have grown to their maximum sizes and can stretch no further, extra space may be left over in the group. An additional property can be used to dictate how any additional space should be distributed between objects. The CSS property box-pack has the possible values of left, right, top, bottom, center, justify and inherit. The default is justify.

In the above example, the button is centered within the group using the box-align and box-pack properties together. The former centers the button vertically, and the latter centers the button horizontally.

8.4.6 Overflow

Items within a group may use the CSS overflow property to obtain horizontal and vertical scrollbars as needed. Flexible objects that shrink below their minimum intrinsic size (but that still have a size greater than a specified CSS minimum) can display scrollbars using the overflow property. If overflow is not specified, the object will be clipped instead.

8.4.7 Inlines and Blocks

Whether an element is inline or block when placed directly inside a group is irrelevant. Objects will be flowed horizontally or vertically based off the box-orient property.

When any raw text nodes are encountered directly inside a group, an anonymous block is constructed to wrap the text. This anonymous block then participates in the layout as a single item.

8.5 Multiple Sub-forms Or Sub-pages

Editorial note: Raman March 12, 2001
Notice that we originally started by creating an equivalent of fieldset--but given the present design of the XForms UI layer, and given that conditional construct case can take either group or html:div elements, there is little left in this construct that is additional to what is in XHTML html:div. I therefore suggest simply reusing html:div--perhaps bind XForms specific behaviors through CSS e.g., a stack of cards for example? The way I am thinking of this is that whether it is a stack of cards shown one at a time, or a sequence of tab dialogs is a presentation issue and might therefore be best left to CSS as we have done with the rest of the presentational issues in XForms.

8.5.1 Subpages

Subpages provide a means to present XForms one bit at a time, breaking a complex task into smaller, simpler parts. Presentation of a subpage can occupy the entire "page" or just part of a page. Different presentations are possible, e.g. a stack of pages with visible name tags, or as a set of buttons for flipping through the stack or navigating directly to a particular subpage. One possible representation is a formset element enclosing one or more subpage elements, each of which starts with a caption element.

As the name implies subpage is not specific to XForms--our intent is to design subpage so that it can be used within XForms--and more generally within XHTML to create presentations where document views are presented to progressively reveal the document structure and content.