# FormLayoutElement > Full API (methods, signatures, descriptions): see [api-reference.md](../../skills/vaadin-playwright-test/api-reference.md). This note covers only behaviour that isn't obvious from the signatures. `vaadin-form-layout` is purely structural: it has no value, no selection and no state a user can change. What is worth asserting is the outcome of its layout algorithm — how many columns it renders at the current width, where it puts the labels, and which fields it is positioning. That is the whole surface. ## Two layout modes, one API `FormLayout` lays out in one of two modes, and `getColumnCount()` / `getLabelPosition()` answer for whichever one is active: | Mode | Enabled by | Columns come from | Labels are aside when | |------|------------|-------------------|-----------------------| | responsive steps (default) | nothing — it is the default | the `responsiveSteps` entry matching the layout's width | that step's `labelsPosition` is not `top` | | auto-responsive | `setAutoResponsive(true)`, or the `defaultAutoResponsiveFormLayout` feature flag | the CSS grid columns the layout actually created | `setLabelsAside(true)` *and* the layout is wide enough for them | In auto-responsive mode `responsiveSteps` is ignored by the component, and so is ignored here. ```java FormLayoutElement layout = FormLayoutElement.getById(page, "address-form"); layout.assertColumnCount(2); layout.assertLabelPosition(FormLayoutElement.LABEL_POSITION_ASIDE); ``` ## Column count is derived, not read off a property The component exposes no property or attribute holding the current column count, so `getColumnCount()` recomputes it the same way the component does: walking `responsiveSteps` and keeping the last one whose `minWidth` still fits the layout, or counting the rendered CSS grid tracks in auto-responsive mode. Two consequences: - The value tracks the layout's **own** width (`offsetWidth`), not the viewport. A layout inside a narrow container stays at one column no matter how wide the browser window is. - With responsive steps the value is derived from the steps directly, so it is correct even before the component has finished reacting to a resize. `assertColumnCount(int)` and `assertLabelPosition(String)` still retry, which is what makes them safe right after `page.setViewportSize(...)` in auto-responsive mode, where the answer does depend on the rendered grid. ```java page.setViewportSize(1600, 900); layout.assertColumnCount(3); page.setViewportSize(600, 900); layout.assertColumnCount(1); layout.assertLabelPosition(FormLayoutElement.LABEL_POSITION_TOP); ``` To make a test deterministic, give the layout a container whose width depends only on the viewport (`40vw`, say) rather than relying on whatever width the surrounding application layout happens to leave. ## `getLabelPosition()` answers for the layout, not for one field It reports where the layout *tells* its form items to put their labels. A layout built from plain fields rather than `FormItem`s still answers — the fields simply ignore the instruction, since only `vaadin-form-item` renders a label the layout controls. With responsive steps the component reflects the same decision onto each form item as a `label-position="top"` attribute (absent when labels are aside), so the two agree: ```java layout.assertLabelPosition(FormLayoutElement.LABEL_POSITION_TOP); assertThat(layout.getFormItems().first()).hasAttribute("label-position", "top"); ``` In auto-responsive mode there is no such attribute — the position is driven by CSS custom properties — so `getLabelPosition()` is the only way to read it. ## `getFields()` flattens rows and skips line breaks A field is whatever occupies one cell of the layout: a plain component, or a `vaadin-form-item` wrapping a label and a field. Two kinds of child are not fields and are filtered out: - `
`, which only forces a row break. - ``, an explicit row grouping in auto-responsive mode. Its children are returned instead, so `addFormRow(a, b)` twice yields four fields, in document order. ```java // layout.addFormRow(street, number); layout.addFormRow(city, country); layout.assertFieldCount(4); assertThat(layout.getField(0)).hasText("Street"); ``` The lookup uses an XPath union rather than a CSS child selector: Playwright's CSS pierces the shadow DOM, so `> *` would also match the layout's internal wrapper element and inflate every count by one. `getFormItems()`, by contrast, matches `vaadin-form-item` anywhere inside the layout, whether or not the items sit in rows.