# Form Form controls style themselves. A bare ``, ``, or `` is a finished 40px control with hover, focus, disabled, and readonly states. Checkboxes and radios are custom-drawn. The `.field` wrapper adds label and help/error structure, and `form.is-grid` gives a two-column layout. This is `form.css` in `@layer components`. Because the bare styling is applied with `:where()` at zero specificity, any class you add wins. Modifiers go **on the control element**, not the wrapper. ## Bare controls ```html One Two ``` Text inputs (all the common `type`s), textarea, and select share the 40px chrome, a `--rule` border that strengthens on hover, and an accent border plus a 1px ring on focus. `` is taller (min 6rem) and resizes vertically. `` draws a custom caret (the `--select-caret` glyph). Disabled and readonly controls get a soft fill. ## A form laid out as a row A bare form is a one-column grid with a gap. Lay it out however you like and the gap goes with the layout, because it belongs to the form rather than to its children: ```html Add ``` `display: flex` on the form does the same thing, and so does any grid of your own. There is nothing to switch off first: no rule puts a vertical step on the children, so nothing is left behind to push a button below the input beside it. Set your own `gap` to override the inherited one. ## Checkbox and radio `` and `` are custom-drawn: an 18px box (square for checkbox with `--radius-xs`, round for radio), a strong border that turns accent on hover, and an accent fill when checked. The checkbox draws its check from the `--checkbox-check` glyph; the radio draws its dot with a gradient in `--accent-ink`. ```html Email me updates Monthly ``` ## Sizes and states (on the control) | Class | Effect | |---|---| | `is-sm` | 32px control | | `is-lg` | 48px control | | `is-error` | Danger border (and danger focus ring) | | `is-ok` | Success border | ```html ``` ## The field wrapper `.field` wraps a label, a control, and help or error text into a labeled field: ```html Email We'll never share it. ``` Parts: | Selector | Role | |---|---| | `.field > label` | The field label | | `.field > .head` | A label row with a right-aligned slot (baseline-aligned, space-between) | | `.field > .head > label` | The label inside a head row | | `.field > .head > .helper` / `.field > .head > a` | The right-aligned helper or link (e.g. "Forgot?") | | `.hint` | Small `--ink-soft` helper text. Inside a field it sits below the control | | `.error` | Danger-colored error text. Inside a field it sits below the control | | `.field.is-full` | Spans both columns in a grid form | ```html Password Forgot? Password is required. ``` `.hint` and `.error` work anywhere, not only inside a `.field`. An error that belongs to the whole form rather than to one input goes in the form: ```html That email and password do not match. ... ``` The only thing `.field` adds is the margin that spaces the text under a control. Put `is-error` on the input as well when the error points at one field, so the control gets the danger border and focus ring. ## Grid form `` lays fields out in two columns with consistent gaps, and collapses to a single column at 40rem. Use `.field.is-full` for a field that should span the full width: ```html First name Last name Email ``` ## Fieldset Bare `` gets a `--rule` border and padding; `` renders as a small medium-weight `--ink-soft` label. No classes needed.
We'll never share it.
Password is required.
That email and password do not match.