Frontfire documentation

Form module

Version 2.1.0

Frontfire UI provides a responsive form layout system that is suitable for most data entry scenarios and can be customised for almost every special need.

This module and all of its plugins is available in the Minimal and Complete bundles.

Basic layout

A form consists of a number of input fields and each of them should have a label that explains to the user what input is expected here. There are three common solutions to place the field labels which are summarised as follows:

  1. Place above or below the text input field – Requires more vertical space and extra distance between the fields for a safe association of labels and fields.
  2. Place to the left of the text input field – Saves vertical space but imposes requirements on window width, also the label length is limited and the input fields need separate alignment.
  3. Place inside the text input field as placeholder text – No additional space required but the label is invisible as soon as text is entered in the field which is problematic when opening a pre-filled form.

Option 3 can be ruled out immediately, although it is still used in some places. Option 2 causes almost unsolvable issues with responsive layout because the window width is too limited on mobile devices (in their default portrait orientation). This leaves option 1 as the best compromise, and that is what Frontfire uses. That layout also allows placing per-field validation messages of sufficient length below each field, so that’s a plus, too. To compensate a little for the higher vertical space demand, shorter fields may be pulled on the same line. This can easily be reverted on smller screens where each field uses its own line again.

The following diagram illustrates that form layout.

Form
Form row
Field group (not an element)
Label
Input
Validation message
Field group (not an element)
Label
Input
Validation message
Form row (same as above)

Single-field layout

Text fields

In a simple layout, a field always covers a full row from the left to the right edge. All fields are wrapped in a <div class="form-row"> element. The form-row CSS class provides the basic layout for one or more input fields in one row. The field label must be marked with the label class. A validation error message can be displayed below each field.

There are several CSS classes for special text field styles:

The style of text fields and similar form fields can be customised with the CSS variables that start with “--textbox-”.

Field label

Validation errors

Validation errors are added with the input-validation-error class on the input element and the field-validation-error class on the following label that contains the error message. These classes are automatically set by ASP.NET Core tag helpers.

The style of validation errors can be customised with the CSS variables that start with “--validation-error-”.

Field label
Error message

Checkbox fields

This also works for checkbox fields. For now, the first (label class) element can be left out.

By the way, the Frontfire style for checkbox inputs is optimised for the case that you insert a white-space between the <input type="checkbox"> element and the label text, both children of the <label> element that makes the label text clickable for the checkbox as well. Leaving out that white-space reduces the distance between the checkbox and the text and should be avoided. The spacing is optimised for that white-space because it’s more often easier to add it than to avoid it.

The style of checkboxes and radiobuttons can be customised with the CSS variables that start with “--checkbox-”.

Checkbox or radio button elements created by code can be styled by calling the styleCheckbox() plugin method on them.

Acceptance required.

The label text of checkbox fields should be indented so that a wrapped line does not start at the left edge of the checkbox border but aligned with the text of the first line, right after the checkbox. Add the indent-checkbox CSS class to the <label> element to indent the text.

Multi-field layout

Multiple fields can be placed in a single row. If nothing else is specified, all fields share the row width equally. Error message elements need to be present because each field is made of 3 elements. The grid layout ensures that all parts are placed at the same vertical offset.

First field label
Second field label
Error message

Without validation messages

When no validation messages are used, the document structure can be simplified by leaving them out. The class no-validation must be used for the row in this case. This reduces the number of elements for a field from 3 to 2.

First field label
Second field label

Responsive layout

As explained above, the fields that share a form row need to be arranged below each other when screen space runs out. Now the class require-minitab indicates that the form row switches to a single-field layout when the screen width drops below the width of a small tablet. The following classes are available: require-minitab, require-tablet, require-desktop, require-wide

First field label
Error message
Second field label

Note:
Since this uses CSS media queries, resizing the example box on this page would not help. To see the responsiveness in action, you’ll have to use your browser’s device preview from the developer tools. In Firefox, press Ctrl+Shift+M. In Chrome, press F12 before that. On a mobile device, it may be sufficient to rotate it. This also applies to all following examples.

Custom layout

Individual widths

To set different widths for each field in a row, the CSS property grid-template-columns must be set for the row. This property of the CSS grid layout accepts a list of width values for each column. Common values are 1fr (and other numeric values with the fr unit) for proportional widths, max-content for the content’s desired width, and fixed lengths in pixels or other units. See the CSS specification for details.

First field label
Error message
Second field label with so much text that it needs a second line
First error
Second error

Simpler syntax for column widths

Alternatively, this can be achieved with the syntax known from GridLength in .NET WPF or other XAML dialects. Add the data-column-widths HTML attribute to a <div class="form-row"> element, or call the formRowColumnWidths() plugin method on it, and it will set the column widths accordingly.

Syntax CSS equivalent Description
* 1fr Fills with weight 1
2* 2fr Fills with specified weight
auto max-content Adjusts to content width
50 50px Exact width in pixels
First field
Second field
More text

Added in v2.1.0

CSS definition

Custom (responsive) layouts can be achieved by defining a CSS class for a row that defines the column widths separately. In a CSS stylesheet, different values can be assigned to the class using media queries. In this example, no labels or validation messages can be used because the option fields may be arranged in one or more rows and columns.

Buttons

Most forms have a set of buttons at their end to let the user perform actions. These buttons should be placed in a <div class="buttons"> element for proper spacing.

There are several CSS classes for special button styles:

The style of buttons can be customised with the CSS variables that start with “--button-”.

A separator line between buttons can be added with the <hr> HTML element. This separator only works in <div> or <span> elements with the buttons class.

Text labels can be added in a buttons row with the label class that vertically centers the text in the row.

First field label
Second field label
Actions:
Link button

The buttons will wrap in another line and keep their spacing if they won’t fit all in one row. You can also use the buttons class outside of traditional forms. To remove the default top margin that separates the buttons from the form fields, add the universal no-top-margin CSS class.

The buttons can be horizontally centred with the center CSS class.

Buttons with an icon

As already shown above, an icon can be used in a button to visually assist the button text. Just add a regular <i> element before the text as you would normally. There should be a white-space between the icon and the text, similar to checkboxes and their label text. The spacing is optimised for that white-space because it’s more often easier to add it than to avoid it, e.g. when writing the icon and text on separate code lines.

The icon can also be defined as an <svg> element with an embedded vector graphic. This is often easier for simple graphics that are not used much elsewhere. Be sure to give it the icon CSS class to apply the same spacing to it. This class also sets the graphic’s fill style to the same as the text colour so that it adapts to different styles and the dark theme seamlessly.

The icon can also be placed at the right side of the button, after the text. This is more appropriate for some icons like a right-arrow to indicate the continuation of a process. There can also be a loading indicator at the right side of the button. For proper spacing (see below), the button needs the icon-right CSS class when the button is at the right side instead of the left.

The distance between the icon and the text is increased a little for visual reasons. This is more needed for Font Awesome icons, less for the Material Symbols included in this documentation. This distance is applied on the right side for left icons, and on the left side for right icons. This single-side margin will off-centre an icon when there is no text at all. To avoid that and keep the icon perfectly centred, add the icon-only CSS class to the button. (The first icon-only button in the following example lacks this class to demonstrate the issue.)

As you might see, the loading indicator needs some individual colour tweaking for the different backgrounds when used in a button, especially for the inverted button types. This is not shown here for the brevity of the example.

Button groups

Buttons can be placed in a group without a gap between them. You can mix <button> elements with button-styled hyperlinks (<a>) freely. Here the entire buttons container makes a button group:

attach

Only some of the buttons can be grouped together by using a separate container element with the group class among other buttons:

attach

The style of button group separators can be customised with the CSS variables that start with “--button-group-separator-”.

Like <a> links can be styled as buttons, a <button> or <input type="button"> and similar types can also be styled as links by adding the link CSS class. They are not quite the same because their text selection and drag behaviour remains unchanged and differs from each other.

Real link

Tree-state checkboxes

While checkboxes in HTML support the third, indeterminate state, that represents an unset value or a set of inconsistent values by setting the indeterminate property, it cannot be reached by user interaction. Frontfire allows this be adding the three-state CSS class to the checkbox input element, or alternatively calling the threeState() plugin method on it. Any click on the checkbox will then cycle through all three states and allow the user to reach the indeterminate state directly.

The indeterminate state can be set through code, but then the threeState() method must be called again on the checkbox element to update its internal state for correct cycling through the states by the user.

Radio button group

Frontfire provides the radio-group CSS class to arrange multiple radio buttons next to each other with a gap between them that is larger than the gap between the radio button and its label. The alignment of the buttons can be changed to the centre or right side with the additional CSS classes center or right, respectively.

Numeric spinners

Any numeric input field like <input type="number"> will be converted into a touch-friendly numeric spinner with big decrement and increment buttons. Input elements created by code can be enhanced by calling the spinner() plugin method on them. The buttons are repeat-buttons so you can long-press them and the value is continuously decremented or incremented automatically, at an increasing speed (within limits).

The spinner can be enabled and disabled by setting the disabled property of the input element by any means (through Frontfire or the native DOM API). The control buttons will follow the disabled state automatically.

The spinner can be shown and hidden by setting the Frontfire.visible property of the input element. Alternatively, the Frontfire methods show(), hide() and toggle() can be called. Other ways like manipulating the style.display property directly will not work. The added buttons will be shown or hidden along with the input element.

Value range

The spinner supports the usual range limits with the min and max attributes. Any decrement or increment through the buttons beyond that valid range will be rejected.

The step attribute is also supported and behaves like the browser-native implementation. This attribute is, like min and max, a validation attribute. That means that manually typed values that do not satisfy these requirements will be rejected by the browser and the form will not be submitted. If you only want to use the step as an input aid but still accept any other values, use the data-step attribute instead. It will be considered by the spinner but not by the browser. The same applies to the data-min and data-max attributes. Use those to limit the range reachable by the buttons but still allow other manual input.

Exponential steps

The spinner also supports exponential steps with the data-step-factor attribute. This factor will be applied to the value with each button click, instead of a linear addition or subtraction. There is no corresponding attribute in the HTML standard, so the data attribute is the only option here.

(Factor 10)

(Factor 2)

Options

The following options are available:

Name Type Description Default
buttons Boolean Indicates whether the increment/decrement button are added to the input element. If set to false, the ArrowUp/ArrowDown keys will also be disabled and no longer change the value to the nearest step. true

Segmented inputs

With labels

A label can be placed before and/or after an input field to further describe its meaning. This can be a value prefix that is never typed in, or the unit of a numeric value. Wrap the input field in an element with the segmented-input CSS class. Any labels (before or after the input) are marked with the label class.

The style of the labels can be customised with the CSS variable --input-label-background.

AX-
AX-
days

The border and background of a label can be removed with the additional no-background CSS class.

days

With buttons

A segmented input can also bind one or multiple buttons with an input field. The button(s) can provide a specific action on the input data, like a lookup or details view.

To combine multiple buttons with a separator line, put them in a <span class="group"> element like with a button group. <button> and <a class="button"> elements can be mixed in the group as usual.

pen-fill

With icons

You can also insert icons or a loading indicator at the start or end of the input field. Add the icon-left CSS class to the wrapper element to have the child icon element be placed at the left end within the input field, or the icon-right class for the right end. The element of a left icon must be placed before the input field, a right icon must be placed after the input field in the document. Both, a left and right icon, cannot be combined.

Telephone number
call-fill
Second field
sensors
Third field

Toggle buttons

A toggle button is a button that switches between an active and inactive state with each click. The active state is visualised by a contrast colour and it can mean the permanent activation of a certain function. To create a toggle button automatically at page loading, use a checkbox and add the toggle-button CSS class to it. To create it by code, call the toggleButton() plugin method on a checkbox element.

The checkbox element will be hidden and replaced by the new button. But the checkbox is still there and it remains the element you should use to determine or change the current state. Just get or set its checked property as usual.

Note:
When setting the checked property, the change event must be triggered to update the view, because there is no way to detect a change of that property!

The style of the active state buttons can be customised with the CSS variables that start with “--button-active-”.

The toggle button can be enabled and disabled by setting the disabled property of the checkbox element by any means (through Frontfire or the native DOM API). Since it was visibly replaced by the button, that button will follow the disabled state automatically.

The toggle button can be shown and hidden by setting the Frontfire.visible property of the checkbox element. Alternatively, the Frontfire methods show(), hide() and toggle() can be called. Other ways like manipulating the style.display property directly will not work. Since it was visibly replaced by the button, that button will be shown or hidden instead of the checkbox element.

Styles

Additional CSS classes can be added to the checkbox element besides toggle-button as for regular buttons: icon-only, icon-right, narrow, transparent.

Events

When an HTML <input type="checkbox"> element is replaced, the visible element is not the original element that was in the document. To make it easier to use certain events with the UI element, they are forwarded to the original <input type="checkbox"> element using the Frontfire.forwardUIEvents() method.

The active state of the toggle button is changed on the click event, so you can listen on that to know when the state has changed.

Events:

Repeat buttons

A repeat button is a button that does not only trigger a single click event after pressing and releasing it, but that continuously triggers events while the button is still pressed. Add the repeat-button CSS class to a button element, or call the repeatButton() plugin method on it, to enable the feature. It then triggers a repeatclick repeatedly, starting slowly and turning faster by the time, until a minimum interval is reached.

0

Options

The following options are available:

Name Type Description Default
focus Boolean Indicates whether the button is focused when clicked. true

Auto-height textarea

The <textarea> element is a multi-line text input field. Its size can be specified and the user may resize its width and/or height interactively. But often, it would be helpful if the text field just goes out of the way and sets its size automatically to fit its current content. This is what the auto-height plugin does.

Add the auto-height CSS class to a <textarea> element, or call the autoHeight() plugin method on it, and it will change its height automatically. It requires JavaScript to function but relies solely on CSS for proper resizing and precise measuring.

Options

The following options are available:

Name Type Description Default
extraRows Number The number of empty rows to show after the input content. 0
maxRows Number The maximum number of rows to show for very long content. If unset, the textarea will expand infinitely and will never show a scroll bar. undefined
minRows Number The minimum number of rows to show for an empty input. 3

Auto-select text fields

Some text fields are meant to be copied only, especially when they are readonly and cannot be modified by the user. In these cases, the content can be selected automatically when clicking on or focusing the field element. Add the auto-select CSS class to a text input field, or call the autoSelect() plugin method on it, to activate this behaviour.

Form submit lock

Sometimes the processing of form data takes a bit time until the next page is loaded. During that time, the only visual feedback that the user sees is a page loading indicator in the browser’s tab header. Impatient users might click on the button a second time while the data is still being processed. Defective mouse buttons might also accidentally cause a double-click on the button when actually clicked just once. All of this may result in the form to be submitted multiple times and the corresponding action to run more than once, too.

To avoid these situations, the button must be locked, or disabled, after clicking it to prevent another accidental or premature form submit. This button deactivation also provides more visual feedback to the user, so that they know the input was successful. If the button has an icon in an <i> element, that icon will be replaced with a loading indicator for as long as the button is disabled. In case the server does not respond or another failure occurs, the button will be re-enabled for safety after a configurable timeout.

Add the submit-lock CSS class to a <button type="submit"> or <input type="submit"> element, or call the submitLock() plugin method on it, and it will add the form submit behaviour.

Direct control with plugin methods:

The form in the above example will submit to the following iframe to demonstrate how the originating page remains open. This has the same effect as if the form response would not load in some time.

Options

The following options are available:

Name Type Description Default
timeout Number The lock timeout, in seconds. 30

Plugin methods

This plugin provides methods to control the button state directly.

lock

Locks the button immediately. This includes disabling the button, replacing the icon and automatically unlocking after the specified timeout. If no timeout was specified, the default timeout option value for the button is used. If the showLoadingIndicator parameter is set to true, the icon in the button (if any) is always replaced with the loading indicator, not only when the button was clicked.

F("#submit-button").submitLock.lock();

showLoadingIndicator parameter added in v2.1.0

unlock

Unlocks the button immediately. This includes enabling the button and restoring the icon.

F("#submit-button").submitLock.unlock();

Overflow buttons

Normally, a buttons panel wraps to fit all buttons. If space is at a premium like on mobile device screens, it can be better to shrink the buttons to fit them in a single row. Only buttons with an icon and text can be shrunk. First the text of the right-most button is truncated, then its text is completely removed. This process repeats for all suitable buttons from right to left, until all buttons fit in a row. This feature is enabled by adding the overflow-buttons CSS class to a <div class="buttons"> element.

If the icon of a button has the additional narrow-only CSS class, it will not be shown if the text is still there, but only as a replacement when the text was hidden. Providing an icon with this class is a way to also shrink buttons that normally have no icon.

As the width of the buttons can change on user interaction, the button visibilities needs to be updated at appropriate times. This can be triggered with the update() plugin method. See the descriptions of the plugin methods below.

cross Cancel

Plugin methods

This plugin provides methods to control the layout.

update

Updates the button visibilities for a buttons div. This needs to be called after updating the contents of the div, like adding/removing buttons. It is called automatically after the window has been resized.