> Markdown version of [Form Layout](https://vaadin.com/docs/next/components/form-layout). Section index: [llms.txt](https://vaadin.com/docs/next/components/llms.txt)

# 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.

**Flow** — `FormLayoutBasic.java`

```java
TextField firstName = new TextField("First name");
TextField lastName = new TextField("Last name");
EmailField email = new EmailField("Email address");
PasswordField password = new PasswordField("Password");
PasswordField confirmPassword = new PasswordField("Confirm password");

FormLayout formLayout = new FormLayout();
formLayout.setAutoResponsive(true);
formLayout.addFormRow(firstName, lastName);
formLayout.addFormRow(email);
formLayout.addFormRow(password, confirmPassword);
```

**React** — `form-layout-basic.tsx`

```tsx
return (
  <FormLayout style={{ width: '100%' }} autoResponsive>
    <FormRow>
      <TextField label="First name" />
      <TextField label="Last name" />
    </FormRow>
    <FormRow>
      <EmailField label="Email address" />
    </FormRow>
    <FormRow>
      <PasswordField label="Password" />
      <PasswordField label="Confirm password" />
    </FormRow>
  </FormLayout>
);
```

**Lit** — `form-layout-basic.ts`

```typescript
return html`
  <vaadin-form-layout style="width: 100%" auto-responsive>
    <vaadin-form-row>
      <vaadin-text-field label="First name"></vaadin-text-field>
      <vaadin-text-field label="Last name"></vaadin-text-field>
    </vaadin-form-row>
    <vaadin-form-row>
      <vaadin-email-field label="Email address"></vaadin-email-field>
    </vaadin-form-row>
    <vaadin-form-row>
      <vaadin-password-field label="Password"></vaadin-password-field>
      <vaadin-password-field label="Confirm password"></vaadin-password-field>
    </vaadin-form-row>
  </vaadin-form-layout>
`;
```

Form Layout automatically adjusts how fields are laid out in columns and rows to utilize the available space and avoid overflow. There are two discrete layouting modes that determine how this works:

- [Auto-responsive mode](#auto-responsive-mode), based on column width

- [Responsive steps mode](#responsive-steps-mode), based on defined breakpoints

> **Note: Default mode depends on feature flag**
>
> The default mode depends on the [feature flag](https://vaadin.com/docs/next/flow/configuration/feature-flags.md) `defaultAutoResponsiveFormLayout`. When enabled, auto-responsive mode is the default; otherwise, responsive steps mode is the default.

## <a id="auto-responsive-mode"></a>Auto-Responsive Mode

In auto-responsive mode, Form Layout automatically determines the appropriate number of columns based on the [column width](#column-width) and spacing, and the available horizontal space.

**Flow**

```java
formLayout.setAutoResponsive(true);
```

**React**

```tsx
<FormLayout autoResponsive>
```

**Lit**

```html
<vaadin-form-layout auto-responsive>
```

> **Note: Feature Flag Controls Default Mode**
>
> Auto-responsive mode can be set as default by setting the [feature flag](https://vaadin.com/docs/next/flow/configuration/feature-flags.md) `defaultAutoResponsiveFormLayout` to true.

The sections below describe features available in auto-responsive mode.

### <a id="form-rows"></a>Form Rows

In auto-responsive mode, all fields are laid out in a single column by default. To render multiple fields side-by-side, i.e. in multiple columns, they can be grouped into Form Rows.

**Flow** — `FormLayoutBasic.java`

```java
TextField firstName = new TextField("First name");
TextField lastName = new TextField("Last name");
EmailField email = new EmailField("Email address");
PasswordField password = new PasswordField("Password");
PasswordField confirmPassword = new PasswordField("Confirm password");

FormLayout formLayout = new FormLayout();
formLayout.setAutoResponsive(true);
formLayout.addFormRow(firstName, lastName);
formLayout.addFormRow(email);
formLayout.addFormRow(password, confirmPassword);
```

**React** — `form-layout-basic.tsx`

```tsx
return (
  <FormLayout style={{ width: '100%' }} autoResponsive>
    <FormRow>
      <TextField label="First name" />
      <TextField label="Last name" />
    </FormRow>
    <FormRow>
      <EmailField label="Email address" />
    </FormRow>
    <FormRow>
      <PasswordField label="Password" />
      <PasswordField label="Confirm password" />
    </FormRow>
  </FormLayout>
);
```

**Lit** — `form-layout-basic.ts`

```typescript
return html`
  <vaadin-form-layout style="width: 100%" auto-responsive>
    <vaadin-form-row>
      <vaadin-text-field label="First name"></vaadin-text-field>
      <vaadin-text-field label="Last name"></vaadin-text-field>
    </vaadin-form-row>
    <vaadin-form-row>
      <vaadin-email-field label="Email address"></vaadin-email-field>
    </vaadin-form-row>
    <vaadin-form-row>
      <vaadin-password-field label="Password"></vaadin-password-field>
      <vaadin-password-field label="Confirm password"></vaadin-password-field>
    </vaadin-form-row>
  </vaadin-form-layout>
`;
```

Form Rows automatically wrap their contents into multiple rows if the layout doesn’t have enough columns to fit them on a single row.

> **Note: UX Tip: Group Related Fields Into Rows**
>
> Forms are easier to understand if fields are grouped into rows based on how closely related they are, rather than arbitrarily. As an example, first name and last name are typically placed on the same row, while a date-of-birth field would typically be on a different row.

### <a id="label-position"></a>Label Position

By default, labels are rendered above the field. Labels can be rendered next to the field by wrapping fields into Form Items and switching to labels-aside mode.

**Flow** — `FormLayoutLabelsAside.java`

```java
TextField firstName = new TextField();
TextField lastName = new TextField();
EmailField email = new EmailField();

FormLayout formLayout = new FormLayout();
formLayout.setAutoResponsive(true);
formLayout.setLabelsAside(true);
formLayout.addFormItem(firstName, "First name");
formLayout.addFormItem(lastName, "Last name");
formLayout.addFormItem(email, "Email address");
```

**React** — `form-layout-labels-aside.tsx`

```tsx
return (
  <FormLayout style={{ width: '100%' }} autoResponsive labelsAside>
    <FormItem>
      <label slot="label">First name</label>
      <TextField />
    </FormItem>
    <FormItem>
      <label slot="label">Last name</label>
      <TextField />
    </FormItem>
    <FormItem>
      <label slot="label">Email address</label>
      <EmailField />
    </FormItem>
  </FormLayout>
);
```

**Lit** — `form-layout-labels-aside.ts`

```typescript
return html`
  <vaadin-form-layout style="width: 100%" auto-responsive labels-aside>
    <vaadin-form-item>
      <label slot="label">First name</label>
      <vaadin-text-field></vaadin-text-field>
    </vaadin-form-item>
    <vaadin-form-item>
      <label slot="label">Last name</label>
      <vaadin-text-field></vaadin-text-field>
    </vaadin-form-item>
    <vaadin-form-item>
      <label slot="label">Email address</label>
      <vaadin-email-field></vaadin-email-field>
    </vaadin-form-item>
  </vaadin-form-layout>
`;
```

The field label must be applied on the Form Item rather than the field itself.

When the Form Layout’s width isn’t sufficient to render labels next to fields, it automatically reverts back to rendering them above fields.

> **Note: UX Tip: Labels Aside Work Best In Single Column Forms**
>
> Forms with labels next to the fields can be confusing if fields are rendered in multiple columns. Although Form Layout supports combining side-labels with multiple columns, this combination is not recommended.

The width of side labels can be configured with the `--vaadin-form-layout-label-width` CSS property. The Flow API also has a dedicated `setLabelWidth` API for this.

### <a id="column-width"></a>Column Width

All columns in a Form Layout have the same width, which can be configured to any CSS length value in absolute or font-relative units like `px`, `pt`, `em`, `rem`, or `ch` (percentages and length keywords like `auto` or `min-content` are not supported).

**Flow**

```java
formLayout.setColumnWidth("8em");
```

**React**

```tsx
<FormLayout columnWidth="8em">
```

**Lit**

```html
<vaadin-form-layout column-width="8em">
```

Additionally, columns can be set to expand to fill any remaining available space in the layout:

**Flow** — `FormLayoutExpandColumns.java`

```java
TextField firstName = new TextField("First name");
TextField lastName = new TextField("Last name");
EmailField email = new EmailField("Email");
PasswordField password = new PasswordField("Password");
PasswordField confirmPassword = new PasswordField("Confirm password");

FormLayout formLayout = new FormLayout();
formLayout.setAutoResponsive(true);
formLayout.setColumnWidth("8em");
formLayout.setExpandColumns(true);
formLayout.addFormRow(firstName, lastName);
formLayout.addFormRow(email);
formLayout.addFormRow(password, confirmPassword);
```

**React** — `form-layout-expand-columns.tsx`

```tsx
return (
  <FormLayout style={{ width: '100%' }} autoResponsive columnWidth="8em" expandColumns>
    <FormRow>
      <TextField label="First name" />
      <TextField label="Last name" />
    </FormRow>
    <FormRow>
      <EmailField label="Email address" />
    </FormRow>
    <FormRow>
      <PasswordField label="Password" />
      <PasswordField label="Confirm password" />
    </FormRow>
  </FormLayout>
);
```

**Lit** — `form-layout-expand-columns.ts`

```typescript
return html`
  <vaadin-form-layout style="width: 100%" auto-responsive column-width="8em" expand-columns>
    <vaadin-form-row>
      <vaadin-text-field label="First name"></vaadin-text-field>
      <vaadin-text-field label="Last name"></vaadin-text-field>
    </vaadin-form-row>
    <vaadin-form-row>
      <vaadin-email-field label="Email address"></vaadin-email-field>
    </vaadin-form-row>
    <vaadin-form-row>
      <vaadin-password-field label="Password"></vaadin-password-field>
      <vaadin-password-field label="Confirm password"></vaadin-password-field>
    </vaadin-form-row>
  </vaadin-form-layout>
`;
```

This is typically combined with expanding fields to fill the full width of their columns, as described below.

### <a id="expanding-fields-to-fill-their-columns"></a>Expanding Fields to Fill Their Columns

In auto-responsive mode, fields do not fill the columns they’re in by default (although they are prevented from overflowing them). This can be changed by enabling field expansion:

**Flow** — `FormLayoutExpandFields.java`

```java
TextField firstName = new TextField("First name");
TextField lastName = new TextField("Last name");
EmailField email = new EmailField("Email");
PasswordField password = new PasswordField("Password");
PasswordField confirmPassword = new PasswordField("Confirm password");

FormLayout formLayout = new FormLayout();
formLayout.setAutoResponsive(true);
formLayout.setColumnWidth("8em");
formLayout.setExpandColumns(true);
formLayout.setExpandFields(true);
formLayout.addFormRow(firstName, lastName);
formLayout.addFormRow(email);
formLayout.addFormRow(password, confirmPassword);
```

**React** — `form-layout-expand-fields.tsx`

```tsx
return (
  <FormLayout
    style={{ width: '100%' }}
    autoResponsive
    columnWidth="8em"
    expandColumns
    expandFields
  >
    <FormRow>
      <TextField label="First name" />
      <TextField label="Last name" />
    </FormRow>
    <FormRow>
      <EmailField label="Email address" />
    </FormRow>
    <FormRow>
      <PasswordField label="Password" />
      <PasswordField label="Confirm password" />
    </FormRow>
  </FormLayout>
);
```

**Lit** — `form-layout-expand-fields.ts`

```typescript
return html`
  <vaadin-form-layout
    style="width: 100%"
    auto-responsive
    column-width="8em"
    expand-columns
    expand-fields
  >
    <vaadin-form-row>
      <vaadin-text-field label="First name"></vaadin-text-field>
      <vaadin-text-field label="Last name"></vaadin-text-field>
    </vaadin-form-row>
    <vaadin-form-row>
      <vaadin-email-field label="Email address"></vaadin-email-field>
    </vaadin-form-row>
    <vaadin-form-row>
      <vaadin-password-field label="Password"></vaadin-password-field>
      <vaadin-password-field label="Confirm password"></vaadin-password-field>
    </vaadin-form-row>
  </vaadin-form-layout>
`;
```

If only certain fields should expand, this can be achieved by setting their widths to 100%.

> **Note: UX Tip: Fields Should Match Their Typical Content Length**
>
> Although a uniform field size may look nice, matching field widths to the typical length of their contents makes it easier to find the correct field and the form easier to understand. This can be achieved by leaving field expansion disabled, or by using [column span](#column-span) to determine the relative widths of fields.

### <a id="column-limit"></a>Column Limit

The number of columns can be limited by setting the maximum column count.

**Flow**

```java
formLayout.setMaxColumns(3);
```

**React**

```tsx
<FormLayout maxColumns="3">
```

**Lit**

```html
<vaadin-form-layout max-columns="3">
```

## <a id="responsive-steps-mode"></a>Responsive Steps Mode

In responsive steps mode, columns are defined explicitly for a number of breakpoints, or *steps*, based on the layout’s width, and fields are automatically laid out in the available columns, wrapping to the next row as needed.

The default breakpoint configuration is one column below a layout width of `40em`, and two columns above that.

> **Note: Feature Flag Controls Default Mode**
>
> The [feature flag](https://vaadin.com/docs/next/flow/configuration/feature-flags.md) `defaultAutoResponsiveFormLayout` makes auto-responsive mode the default. With the flag enabled, individual Form Layouts can be switched to responsive steps mode by defining the responsive steps manually.

### <a id="setting-the-breakpoints"></a>Setting the Breakpoints

Each breakpoint defines the minimum layout width at which it is applied, and the number of columns rendered.

The following example sets

- One column when the layout is less than 320 pixels wide

- Two columns when the layout is at least 320 pixels wide

- Three columns when the layout is at least 500 pixels wide

**Flow** — `FormLayoutStepsBasic.java`

```java
TextField firstName = new TextField("First name");
TextField lastName = new TextField("Last name");
EmailField email = new EmailField("Email address");

FormLayout formLayout = new FormLayout();
formLayout.add(firstName, lastName, email);
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));
```

**React** — `form-layout-steps-basic.tsx`

```tsx
const responsiveSteps = [
  // Use one column by default
  { minWidth: '0', columns: 1 },
  // Use two columns, if the layout's width exceeds 320px
  { minWidth: '320px', columns: 2 },
  // Use three columns, if the layout's width exceeds 500px
  { minWidth: '500px', columns: 3 },
];

function renderFormLayout() {
  return (
    <FormLayout responsiveSteps={responsiveSteps}>
      <TextField label="First name" />
      <TextField label="Last name" />
      <EmailField label="Email address" />
    </FormLayout>
  );
}
```

**Lit** — `form-layout-steps-basic.ts`

```typescript
private responsiveSteps: FormLayoutResponsiveStep[] = [
  // Use one column by default
  { minWidth: 0, columns: 1 },
  // Use two columns, if the layout's width exceeds 320px
  { minWidth: '320px', columns: 2 },
  // Use three columns, if the layout's width exceeds 500px
  { minWidth: '500px', columns: 3 },
];

private renderFormLayout() {
  return html`
    <vaadin-form-layout .responsiveSteps="${this.responsiveSteps}">
      <vaadin-text-field label="First name"></vaadin-text-field>
      <vaadin-text-field label="Last name"></vaadin-text-field>
      <vaadin-email-field label="Email address"></vaadin-email-field>
    </vaadin-form-layout>
  `;
}
```

Note that

- The smallest breakpoint should always be at zero pixels;

- The breakpoints must be ordered by width.

### <a id="label-position-2"></a>Label Position

By default, labels are rendered above the field. Labels can be rendered next to the field by wrapping the fields into Form Items.

In responsive steps mode, fields wrapped in Form Items render their fields on the side by default, unless the breakpoint configuration defines the label position to be above the fields.

**Flow** — `FormLayoutStepsLabelsAside.java`

```java
TextField firstName = new TextField();
TextField lastName = new TextField();
EmailField email = new EmailField();

FormLayout formLayout = new FormLayout();
formLayout.setLabelWidth("92px");
formLayout.addFormItem(firstName, "First name");
formLayout.addFormItem(lastName, "Last name");
formLayout.addFormItem(email, "Email address");

// This is the default configuration shown for demonstration purposes
// formLayout.setResponsiveSteps(
//         new ResponsiveStep("0", 1, ResponsiveStep.LabelsPosition.TOP),
//         new ResponsiveStep("20em", 1),
//         new ResponsiveStep("40em", 2));
```

**React** — `form-layout-steps-labels-aside.tsx`

```tsx
// This is the default configuration shown for demonstration purposes
// const responsiveSteps: FormLayoutResponsiveStep[] = [
//   { minWidth: 0, columns: 1, labelsPosition: 'top' },
//   { minWidth: '20em', columns: 1 },
//   { minWidth: '40em', columns: 2 },
// ];

function renderFormLayout() {
  return (
    <FormLayout style={{ '--vaadin-form-layout-label-width': '92px' }}>
      {/* Wrap fields into form items, which displays labels on the side by default */}
      <FormItem>
        <label slot="label">First name</label>
        <TextField />
      </FormItem>
      <FormItem>
        <label slot="label">Last name</label>
        <TextField />
      </FormItem>
      <FormItem>
        <label slot="label">Email address</label>
        <EmailField />
      </FormItem>
    </FormLayout>
  );
}
```

**Lit** — `form-layout-steps-labels-aside.ts`

```typescript
// This is the default configuration shown for demonstration purposes
// private responsiveSteps: FormLayoutResponsiveStep[] = [
//   { minWidth: 0, columns: 1, labelsPosition: 'top' },
//   { minWidth: '20em', columns: 1 },
//   { minWidth: '40em', columns: 2 },
// ];

private renderFormLayout() {
  return html`
    <vaadin-form-layout style="--vaadin-form-layout-label-width: 92px;">
      <!-- Wrap fields into form items, which
           displays labels on the side by default -->
      <vaadin-form-item>
        <label slot="label">First name</label>
        <vaadin-text-field></vaadin-text-field>
      </vaadin-form-item>
      <vaadin-form-item>
        <label slot="label">Last name</label>
        <vaadin-text-field></vaadin-text-field>
      </vaadin-form-item>
      <vaadin-form-item>
        <label slot="label">Email address</label>
        <vaadin-email-field></vaadin-email-field>
      </vaadin-form-item>
    </vaadin-form-layout>
  `;
}
```

The *default* breakpoint configuration renders Form Item wrapped fields with labels on the side, but reverts to labels above fields when the layout is less than `20em` wide.

Note that

- The field label must be applied on the Form Item rather than the field itself.

- Fields wrapped into Form Items do not match the size of the wrapper by default. To avoid empty space or overflow in the column, set the widths of the fields to 100%.

> **Note: UX Tip: Labels Aside Work Best In Single Column Forms**
>
> Forms with labels next to the fields can be confusing if fields are rendered in multiple columns. Although Form Layout supports combining side-labels with multiple columns, this combination is not recommended.

### <a id="row-breaks"></a>Row Breaks

Fields can be forced to break into multiple rows using html `<br>` line break elements:

**Flow**

```java
formLayout.add(new TextField("First name"));
formLayout.add(new TextField("Last name"));
formLayout.getElement().appendChild(ElementFactory.createBr()); // row break
formLayout.add(new EmailField("Email address"));
```

**React**

```tsx
<FormLayout>
  <TextField label="First name" />
  <TextField label="Last name" />
  <br/> {/* row break */}
  <EmailField label="Email address" />
</FormLayout>
```

**Lit**

```html
<vaadin-form-layout>
  <vaadin-text-field label="First name"></vaadin-text-field>
  <vaadin-text-field label="Last name"></vaadin-text-field>
  <br/> <!-- row break -->
  <vaadin-email-field label="Email address"></vaadin-email-field>
</vaadin-form-layout>
```

### <a id="field-width"></a>Field Width

In responsive steps mode, fields are automatically scaled to fit and fill the columns. Overriding this by setting minimum or maximum width on the field breaks the layout.

To prevent a field from stretching to fill the full width of the column, wrap it in a Form Item. Note that the field may overflow the Form Item and break the layout if its width is larger than the width of the column. To avoid this, set the field’s maximum width to 100%.

## <a id="column-span"></a>Column Span

Fields can span multiple columns. Note that fields wrapped into Form Items must have their columns span set on the Form Item instead of the field itself.

**Flow** — `FormLayoutColspan.java`

```java
TextField streetAddress = new TextField("Street address");
TextField postalCode = new TextField("Postal code");
TextField city = new TextField("City/Town");
TextField country = new TextField("Country");

FormLayout formLayout = new FormLayout();
formLayout.setAutoResponsive(true);
formLayout.setExpandFields(true);
formLayout.setColumnWidth("8em");

FormRow firstRow = new FormRow();
firstRow.add(streetAddress, 3); // colspan 3

FormRow secondRow = new FormRow();
secondRow.add(postalCode);
secondRow.add(city, 2); // colspan 2

FormRow thirdRow = new FormRow();
thirdRow.add(country, 2); // colspan 2

formLayout.add(firstRow, secondRow, thirdRow);
```

**React** — `form-layout-colspan.tsx`

```tsx
return (
  <FormLayout style={{ width: '100%' }} autoResponsive columnWidth="8em" expandFields>
    <FormRow>
      <TextField label="Street address" data-colspan="3" />
    </FormRow>
    <FormRow>
      <TextField label="Postal code" />
      <TextField label="City/Town" data-colspan="2" />
    </FormRow>
    <FormRow>
      <TextField label="Country" data-colspan="2" />
    </FormRow>
  </FormLayout>
);
```

**Lit** — `form-layout-colspan.ts`

```typescript
return html`
  <vaadin-form-layout style="width: 100%" auto-responsive column-width="8em" expand-fields>
    <vaadin-form-row>
      <vaadin-text-field label="Street address" data-colspan="3"></vaadin-text-field>
    </vaadin-form-row>
    <vaadin-form-row>
      <vaadin-text-field label="Postal code"></vaadin-text-field>
      <vaadin-text-field label="City/Town" data-colspan="2"></vaadin-text-field>
    </vaadin-form-row>
    <vaadin-form-row>
      <vaadin-text-field label="Country" data-colspan="2"></vaadin-text-field>
    </vaadin-form-row>
  </vaadin-form-layout>
`;
```

Column span is capped to the number of columns currently in the layout to prevent overflow.

## <a id="ai-form-filler"></a>AI Form Filler

Use the commercial `FormAIController` to let users fill a Form Layout from natural-language input or attached files. See [AI Form Filler Flow](https://vaadin.com/docs/next/components/form-layout/ai-powered.md).

## <a id="miscellaneous"></a>Miscellaneous

### <a id="form-item-usage"></a>Form Item Usage

Form Item is only intended for wrapping individual input field components or native html `<input>` elements. It automatically applies an [`aria-labelledby`](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Reference/Attributes/aria-labelledby) attribute to the element for screen reader support, which only works correctly with input fields and Web Components with an `ariaTarget` property that returns an appropriate element to which the `aria-labelledby` attribute can be applied.

To combine multiple inputs in the same form field, or to provide a label to other elements that lack labels, use [Custom Field](https://vaadin.com/docs/next/components/custom-field.md) instead. A Custom Field can be further wrapped into a Form Item for side-label support.

### <a id="scrolling"></a>Scrolling

Form Layout does not provide its own scroll area. To make a scrollable form, wrap the layout into a [Scroller](https://vaadin.com/docs/next/components/scroller.md), and make sure that its size is undefined in the desired scroll direction.

### <a id="field-focus-order"></a>Field Focus Order

Fields in multi-column Form Layouts always flow from left to right, then down, and the focus order of the fields will match this order. To make a form where focus flows from top to bottom, column by column, split the form into multiple single-column Form Layouts instead.

### <a id="buttons"></a>Buttons

Forms usually have buttons at the bottom for saving or cancelling changes. While these can be placed in the Form Layout itself, it is usually better to put them in a separate layout below the Form Layout. The [Button component documentation](https://vaadin.com/docs/next/components/button.md) provides more recommendations on buttons in forms.

`7B8E4F98-540C-4622-A39F-907C95E9DFFD`
