Form Layout
Form Layout allows you to build responsive forms with multiple columns, and to position input labels above or to the side of the input.
new tab
TextField firstName = new TextField("First name");
TextField lastName = new TextField("Last name");
TextField username = new TextField("Username");
PasswordField password = new PasswordField("Password");
PasswordField confirmPassword = new PasswordField("Confirm password");
FormLayout formLayout = new FormLayout();
formLayout.add(firstName, lastName, username, password,
confirmPassword);
formLayout.setResponsiveSteps(
// Use one column by default
new ResponsiveStep("0", 1),
// Use two columns, if layout's width exceeds 500px
new ResponsiveStep("500px", 2));
// Stretch the username field over 2 columns
formLayout.setColspan(username, 2);
Columns
By default, Form Layout has two columns: it displays two input fields per line. When the layout width is smaller, it adjusts to a single-column.
Custom Layout
You can define how many columns that Form Layout should use based on the screen width. Use the draggable split handle to resize Form Layout’s available space and to test its responsiveness.
new tab
formLayout.setResponsiveSteps(
// Use one column by default
new ResponsiveStep("0", 1),
// Use two columns, if the layout's width exceeds 320px
new ResponsiveStep("320px", 2),
// Use three columns, if the layout's width exceeds 500px
new ResponsiveStep("500px", 3));
A single-column layout is preferable to a multi-column layout. A multi-column layout can be prone to confusion and misinterpretation by the user. However, related fields placed in a line are typically understandable. Examples of this would be first and last name, address fields such as city and postal code, and ranged input for dates, time, and price or cost.
Column Span
When using a multi-column layout, you can define a colspan
for each component. The colspan
determines how many columns a component extends or stretches across.
For example, if you have a Form Layout with three columns and a component’s colspan
is set to 3, it’ll therefore take the entire width of the Form Layout.
Label Position
The built-in labels for input fields are positioned above the input. Form Layout supports side-positioned labels, provided they’re wrapped in Form Items and the label position is set to aside
.
The only reason for wrapping labels in Form Items is to put the labels to the side of the input.
Top
Users complete forms that have top-positioned labels more quickly because they provide a consistent scanning pattern — top-down, as opposed to zigzag — while minimizing the distance between the label and input field.
Top-positioned labels are also less prone to causing layout issues due to variable label lengths, which happens usually in multilingual applications. However, they do result in vertically longer forms. This is why sectioning is important.
Side
Side-positioned labels help reduce a form’s total height. This is especially useful for longer forms and when vertical space is limited.
The positioning of labels on the side is also useful when there’s a need to compare numeric data.
new tab
formLayout.setLabelWidth("60px");
// Use addFormItem instead of add, to wrap fields into form items,
// which displays labels on the side by default
formLayout.addFormItem(revenue, "Revenue");
formLayout.addFormItem(expenses, "Expenses");
formLayout.addFormItem(invoices, "Invoices");
Aim for similar-length labels to keep the distance consistent between the labels and the input fields. Inconsistent spacing can slow the user in completing a form.
Forms that use this position require more horizontal space, which isn’t always ideal in narrow forms. Instead, configure Form Layout to use top-positioned labels when the form has a narrow width.
The width of side-positioned labels can be adjusted using the --vaadin-form-item-label-width
CSS property on the Form Layout element, or with the setLabelWidth()
method on the FormLayout
instance in Flow.
Spacing
Form Layout allows you to configure the spacing between columns, rows, and between the label and input field when labels are positioned on the side.
To configure the spacing, use the following CSS properties on the Form Layout element:
Property | Default Value |
---|---|
|
|
|
|
|
|
Native Input Fields
Form Item allows you to set a label for any type of component that you want to use in a Form Layout. It supports both Vaadin components and native HTML components.
Multiple Fields
Form Item only supports placing a single field inside. Where you need to place multiple fields, Custom Field should be used as a wrapper:
new tab
public class ExpirationField extends CustomField<String> {
private final List<String> MONTHS = IntStream.range(1, 13)
.mapToObj(month -> String.format("%02d", month))
.collect(Collectors.toList());
private final List<String> YEARS = IntStream
.range(LocalDate.now().getYear(),
LocalDate.now().getYear() + 11)
.mapToObj(year -> Integer.toString(year))
.collect(Collectors.toList());
private final Select<String> month = new Select<String>();
private final Select<String> year = new Select<String>();
public ExpirationField() {
HorizontalLayout layout = new HorizontalLayout();
layout.setPadding(false);
layout.setSpacing(false);
layout.getThemeList().add("spacing-xs");
month.setItems(MONTHS);
month.setPlaceholder("Month");
// Set title for screen readers
month.setAriaLabel("Month");
layout.add(month);
year.setItems(YEARS);
year.setPlaceholder("Year");
year.setAriaLabel("Year");
layout.add(year);
add(layout);
}
@Override
protected String generateModelValue() {
String monthValue = month.getValue();
String yearValue = year.getValue();
if (monthValue == month.getEmptyValue()
|| yearValue == year.getEmptyValue()) {
return null;
}
return String.join("/", monthValue.toString(),
yearValue.toString());
}
@Override
protected void setPresentationValue(String expiration) {
if (expiration == null) {
month.setValue(null);
year.setValue(null);
} else {
String[] expirationParts = expiration.split("/");
month.setValue(expirationParts[0]);
year.setValue(expirationParts[1]);
}
}
}
public FormLayoutCustomField() {
FormLayout formLayout = new FormLayout();
formLayout.addFormItem(new ExpirationField(), "Expiration");
add(formLayout);
}
Keeping fields in individual Form Items is preferable. Wrapped fields can be hard to distinguish visually since they usually have no individual label except for a placeholder, which is only visible when the field has no value.
Best Practices
With regards to developing with Form Layout, this section provides some suggestions for better user experiences.
Button Placement
Use the following guidelines for Button placement in forms:
-
Buttons should be placed below the form with which they’re associated.
-
Buttons should be aligned to the left.
-
Primary action should be placed first, followed by other actions, in order of importance.
For more information, see the Button documentation.
7B8E4F98-540C-4622-A39F-907C95E9DFFD