Form
The rhythm of a form: rows, sections and actions that follow their column.
On this page
A form layout sets the rhythm between fields: one distance down the column, short fields side by side, and the buttons that close it at the end. It is a layout, not a component: it draws no surface and holds no state. What it knows is when to stack.
The form is a size container, so its rows and sections follow the column the form is given, not the viewport. The same markup is two columns on a settings page and one column in a narrow dialog. Those thresholds are why this is a class and not a handful of utilities.
Form
<form class="form max-w(480) mx-auto"> <div class="form-row"> <label class="field">First name <input class="input" name="given-name" autocomplete="given-name" value="Ada"> </label> <label class="field">Last name <input class="input" name="family-name" autocomplete="family-name" value="Lovelace"> </label> </div> <label class="field">Email <input class="input" type="email" name="email" autocomplete="email" value="ada@example.com"> <span class="field-hint">We send a receipt here.</span> </label> <label class="field">Message <textarea class="input input-auto" name="message"></textarea> </label> <div class="form-actions"> <button class="btn" type="button">Cancel</button> <button class="btn btn-primary">Send</button> </div></form>#Rows
form-row holds fields that are read as one line: a first and a last name, a city and a postcode. From 28rem of form they share the line in equal columns; below that they stack. Keep a row to two or three short fields.
#Sections
A form-section puts a heading beside the fields it describes. From 40rem of form the heading takes a third of the width and the fields the rest, the way a settings page reads; below that the heading sits above its fields. Sections are parted by a hairline.
Sections
<form class="form w-full"> <section class="form-section" aria-labelledby="form-profile"> <div class="form-heading"> <h3 class="form-title" id="form-profile">Profile</h3> <p class="form-description">Shown on your public page and next to your comments.</p> </div> <div class="form-fields"> <div class="form-row"> <label class="field">First name <input class="input" value="Ada"> </label> <label class="field">Last name <input class="input" value="Lovelace"> </label> </div> <label class="field">Bio <textarea class="input input-auto"></textarea> </label> </div> </section> <section class="form-section" aria-labelledby="form-notify"> <div class="form-heading"> <h3 class="form-title" id="form-notify">Notifications</h3> <p class="form-description">Choose what reaches your inbox.</p> </div> <div class="form-fields"> <label class="check"> <input type="checkbox" class="checkbox" checked>Mentions and replies</label> <label class="check"> <input type="checkbox" class="checkbox">A weekly summary</label> </div> </section> <div class="form-actions"> <button class="btn" type="button">Discard</button> <button class="btn btn-primary">Save changes</button> </div></form>#Actions
form-actions closes the form: buttons at the end of the line, the confirming one last. Below 24rem of form they stack at full width and the confirming button comes first, where the thumb is. Write the buttons in reading order, cancel before confirm; the stylesheet reverses the stack.
In a narrow column
<form class="form max-w(300) mx-auto"> <div class="form-row"> <label class="field">City <input class="input" value="London"> </label> <label class="field">Postcode <input class="input" value="N1 9GU"> </label> </div> <div class="form-actions"> <button class="btn" type="button">Cancel</button> <button class="btn btn-primary">Save address</button> </div></form>#Accessibility
- The form classes are layout only. Labels, hints and errors come from
field; groups of related controls fromfieldset. - Give each section a heading and point the
<section>at it witharia-labelledby, so the group has a name. - The stacked actions change order visually, not in the document: the tab order stays cancel, then confirm.
- A container needs a width from its context. Inside a shrink-to-fit box (an inline-flex parent, a popover without a width) give the form a width.
#Classes
| Class | Description |
|---|---|
form | The column of fields, at one distance, and a size container named form. Its width must come from its context |
form-row | Fields read as one line; they share it in equal columns from 28rem of form and stack below |
form-section | A heading with the fields it describes; from 40rem of form the heading stands beside them at a third of the width. Sections are parted by a hairline |
form-heading | The title and the description of a section |
form-title | The title of a section |
form-description | A sentence under the title of a section |
form-fields | The fields of a section, at the form's distance |
form-actions | The closing buttons, at the end with the confirming one last; below 24rem of form they stack at full width with the confirming one first |
#Custom properties
| Property | Default | Description |
|---|---|---|
--form-gap | 1.25rem | The distance between fields |
#Related
- InputText fields cut into the surface, with labels, hints, errors and groups.
- CheckboxA small native well that fills with ink when checked.
- ButtonA raised control that lifts on hover and sinks when pressed.
- SettingsA short navigation beside the sections of a long form.
- CenteredOne task in the middle of the viewport, alone or beside a panel.