Input field

Single-line text entry. Its sm/md/lg axis shares size.interactive with Button, Select, and SegmentedControl, so controls composed on one row stay aligned. Every state is answered on the border, focus included, so there is no offset ring crowding the label.

Sizes

Height and type move together while the comfortable space.3 field inset stays fixed; medium is the modifier-free default. Field sizes preserve the text column instead of scaling like content-sized Buttons.

ExampleSizeModifierHeightUsage
Small--smsize.interactive.smToolbars, table filters, dense forms
Mediumds-inputsize.interactive.mdForms and most surfaces
Large--lgsize.interactive.lgHigh-emphasis and touch-oriented flows

States

Real DOM drivers set every state; demo classes force the pointer states here and behave identically.

ExampleStateDriverRolesUsage
Restborder.defaulttext.mutedPlaceholder is never essential content
Rest, filledtext.primaryEntered value on surface.page
Hover:hoverborder.hoverThe border answers the pointer
Focus:focus-visiblefocus.ringThe engaged control — the border takes the focus color, no offset ring
Invalid[aria-invalid]status.error.border.fgPair with an error message via aria-describedby
Read-only[readonly]surface.canvasFocusable and copyable, not editable
Disabled:disabledaction.disabled.bg.textExcluded from interaction and the tab order
Input · Types

One recipe across the semantic types (email, password, number, and friends): the type buys the right mobile keyboard, native validation, masking, or steppers — never a different look. The type is an attribute, not a variant.

Usage notes

The control is bare by design — labels, help, and errors compose around it.

VerdictRule
DoGive every input a label: a visible one via FormField, or aria-label when the surrounding context is the label.
DoKeep the placeholder a hint, never a label and never essential content — text.muted sits below AA by design.
DoChoose read-only vs disabled by whether the value still matters: read-only keeps it in the page (focusable, selectable, submitted); disabled removes the control from interaction and the tab order.
DoSet aria-invalid with a message referenced by aria-describedby — never signal errors with color alone.
Don’tDisable an input as validation feedback — show the error on the field instead.