13 · Craft · Forms

Fields do the talking. Labels step back.

13 / 22

Forms are where users work. The chrome around that work should recede — labels in sentence case at body weight, fields with room to breathe, focus as a hairline shift rather than a glow. Errors whisper beneath the field in signal-red. Capitalized mono labels and double-thick borders belong on chrome and chips — not on the input the user is trying to fill.

Primary · Prompt + Name
⏎ to submit · ⇧⏎ for newline
Row · Select · Helper · Error
Fires when the figment publishes a new release.
Handles can't contain spaces.
Checks · Radio · Inline edit
Campaign Q2

Click to edit. No chrome until hover — the title behaves like text, not a form field.

A
Labels are voice, not chrome.

Sentence case, Onest, 13px, regular weight. The label is telling the user what field this is — it should sound like a human naming a thing, not a system shouting a slot name. Mono uppercase belongs on metadata and chips, not on input labels.

B
Focus is a hairline.

1px border from muted to foreground. No glow halos, no ring-2, no box shadows spreading out from the field. The field is already bordered — focus just sharpens the edge it already has.

C
Fields breathe.

11px vertical, 14px horizontal padding. Enough room to aim for, enough to let the value sit on the baseline without feeling trapped. Textareas start at 108px min-height — a full thought fits without resizing.

D
Errors whisper. They don't banner.

Signal-red text below the field, 12px, with a 4px red dot. The field's border tints toward red at 55% mix — visible, not violent. No full-red fills, no alert banners. The field stays editable; the user can fix it in-place.

E
Helper text sits below, not above.

Hints appear after the field — where the user lands after filling it — not between the label and the input. Onest 12px muted. One sentence maximum. If it needs a paragraph, it's a documentation link, not a hint.

F
One ask per row. Two if they're siblings.

A title and its type. A first name and a last. A name and its randomize button. Fields share a row only when reading them together matches how the user thinks about them. Everything else stacks.