In user interfaces, the focus usually refers to keyboard focus. A control is said to have focus when it currently receives keyboard input, whether for text entry or for manipulating the control itself (like using cursor keys to open a dropdown). Browsers usually indicate focus with a highlight:
XForms supports focus with a few constructs:
the <xf:setfocus>
action and the the xforms-focus
event
the DOMFocusIn
and DOMFocusOut
events
This page describes the behaviors associated with focus in the Orbeon Forms XForms engine.
In Orbeon Forms, the following controls accept focus from the user:
xf:input
xf:secret
xf:select
/ xf:select1
xf:trigger
/ xf:submit
xf:textarea
xf:upload
XBL controls with the focus
mode
Focus can only happen on those controls under the following conditions:
The control is relevant.
The control is not read-only.
The control is not hidden, namely.
It is not in a hidden case.
It is not in a closed dialog.
The following controls never accept focus:
xf:output
grouping controls
xf:group
xf:switch
/ xf:case
xf:repeat
xxf:dialog
XBL controls without the focus
mode
NOTE: While grouping controls never accept focus directly, XForms actions can be used to set focus to nested controls (see below).
As a user, you can impact the focus in the following ways:
by clicking inside a control (for example on an input field)
this removes focus from the previously focused control if any
then sets the focus to the clicked control
by clicking outside of any controls
this removes focus from all controls
by tabbing between fields, when enabled by the browser
this removes focus from the previously focused control
then sets the focus to the newly entered control
by clicking outside of a control but within a repeat iteration
if focus was on a control within another repeat iteration, focus is moved to the new iteration's corresponding control
otherwise, focus is removed and the iteration becomes the new iteration
The XForms <xf:setfocus>
action allows the form author to change the focus to a particular control. It is similar to the HTML focus()
function, with handling of grouping controls as a nice bonus feature.
Here is a basic use of the action:
You can also use the action on grouping controls, in which case it will set the focus to the first nested control able to accept focus:
When the grouping control is a switch or a repeat, the focus naturally follows the selected case or the current repeat iteration, respectively. In this example, the focus will be set to the input control in the repeat iteration that matches the current repeat index:
[DEPRECATED SINCE Orbeon Forms 2016.3. Use includes
and excludes
instead.]
The input-only
extension attribute, when set to true
, changes the behavior of the action by allowing focus only on the <xf:input>
control. This means that buttons (<xf:trigger>
) in particular are excluded.
This is convenient in particular to focus on the first control supporting input under a grouping control:
This way, the user can use the keyboard right away, yet the programmer does not have to be specific as to which control must receive focus.
The attribute is an AVT.
[SINCE Orbeon Forms 2016.3]
The includes
and excludes
attribute allow filtering which controls are allowed to receive focus when using <xf:setfocus>
.
includes
list of control QNames to include
include all controls if missing or blank
excludes
list of control QNames to exclude
exclude no controls if missing or blank
These attributes deprecate input-only="true"
which is equivalent to includes="xf:input"
.
This allows focus on all controls except <xf:trigger>
:
This allows focus on <xf:input>
and <xf:textarea>
only:
XForms enforces that, within a repeat, only a control part of the repeat iteration that matches the current repeat index can have focus.
This means that:
if the user clicks on a control within a repeat iteration, the focus changes to that control and the current iteration is adjusted
if the current repeat iteration changes, and focus was on a control within another iteration, the focus as adjusted
When using the <xf:setindex>
action, the following logic takes place if the index changes:
if the control with focus is within the old iteration, focus is removed from that control
if possible (based on relevance, read-only, and visibility), focus is set to the corresponding control in the new iteration
Similarly to <xf:setindex>
, XForms enforces that a control within a hidden case or dialog cannot have focus. If a focused control is within a case or dialog and the case is hidden via <xf:toggle>
or the dialog closed via <xxf:hide>
, focus is removed from that control.
When a dialog is opened with <xxf:show>
, and focus was on a control outside the dialog, focus is first removed.
Then, focus is set to the dialog control itself, which means that the first focusable control within the dialog gets focus. This behavior can be overridden, as described further below.
The <xf:insert>
and <xf:delete>
actions can immediately:
add or remove iterations
change the current repeat index, depending on iterations added, removed, or moved
The following logic takes place:
if the iteration has moved and the focused control is still focusable, keep the focus on that control
if the iteration has moved and the focused control is no longer focusable, remove the focus
if the iteration has been removed
remove focus from the control
try to find the corresponding control matching the current index, as for <xf:setindex>
if the control is found and focusable, focus on it
Lots of things can change during refresh:
controls might become non-relevant
repeat iterations might be added, removed, or move
with the XForms 2 @caseref
attribute, cases can become hidden
Just after refresh, the focus is adjusted accordingly:
for repeats, the same logic that applies to the <xf:insert>
and <xf:delete>
actions takes place
otherwise, if focus was on a control that has become non-relevant, read-only, or hidden, focus is removed
When a dialog opens, you can explicitly focus on a given control upon receiving the xxforms-dialog-open
event. In this example, the form author sets focus on age-input
instead of name-input
(which would receive focus by default as it is the first control):
You can override an XBL component's default focus behavior with an event handler. For example, to run JavaScript upon focus:
Or, to focus to a specific nested control:
In both cases, defaultAction="cancel"
ensures that after the overridden behavior has completed, the default algorithm above does not take place.
These two events can be used to detect whether a control has lost or gained focus. For example:
When the XForms engine determines that a control must receive focus, it starts a sequence of events, as follows:
dispatch DOMFocusOut
to the control that previously had focus, if any
dispatch DOMFocusOut
to the ancestor grouping controls of the control that previously had focus, if any
dispatch DOMFocusIn
to the ancestor grouping controls of the control that is gaining focus, if any
dispatch DOMFocusIn
to the control that is gaining focus, if any
These two events bubble, so you have to be careful with event listeners. Often, it is a good idea to use the target
attribute on event handlers to make sure that focus changes are detected on the expected control:
The xforms-focus
event should usually be considered an internal event used by the xf:setfocus
action. However, it is useful to know about this event in two situations:
to prevent focus from taking place on a control or grouping control
to override the focus behavior, as in the XBL component example described above
refresh models and view if needed
resolve the target control
attribute following Resolving ID References in XForms
dispatch the xforms-focus
event to that control
the control then searches for the actual control to focus, if any, following the algorithm below
Orbeon Forms implements the following XForms 1.1-compatible behavior when receiving xforms-focus
:
For any control:
if the control is non-relevant, read-only, or not visible, processing of the event terminates and the focus is not changed
If the target control is a core form control (such as <xf:input>
):
focus is set to that control
If the target control is one of the following container form control: <xf:group>
, <xf:case>
, <xxf:dialog>
, or an XBL control:
children controls are recursively searched and the first descendant control able to receive focus receives focus
if there is no such control, processing of the event terminates
If the target control is the <xf:switch>
control:
the currently selected child <xf:case>
control is recursively searched and the first descendant control able to receive focus receives it
If there is no such control, processing of the event terminates
If the target control is the <xf:repeat>
control:
the repeat iteration corresponding to the current repeat index is recursively searched and the first descendant control able to receive focus receives it.
if there is no such control, or if there is no iteration, processing of the event terminates
NOTE: the xforms-focus
event does not bubble.