Design system Inputs
Text input
One face for everything typed: text, date, number, telephone, a textarea. The instrument edge on every ground.
.mk-input.mk-field
Overview
The text input is the one-line face for typed facts — text, number and telephone. It rests on the strong grey edge whatever ground it sits on, and its field is white: a field is a field, not a well. Longer prose moves to the text area below.
Usage
- Collect a free-form valueUse Text input when the user must type a value that cannot be represented by a useful closed set of options.
- Choose the face by expected lengthUse the single-line field for concise values and Textarea for prose or content expected to wrap across lines.
- Keep instructions and validation distinctThe label names the value, supporting text explains format or consequence, and validation appears only after the field can be evaluated.
Anatomy
- 1Field label. Sentence case, medium weight — the control
voice. It names exactly one control and is part of the same
<label>, so pressing it focuses the field. - 2Input area. The placeholder marks where entered text will appear. It is a temporary hint, never a replacement for the field label, and disappears as soon as the user types.
- 3The field. White surface, the strong hairline edge, control radius, 44px minimum. Hover and focus warm the border; the resting edge is grey on every ground — the warm resting variant split the family and was repealed.
Variants and states
The size ladder
Three control heights mirroring the button scale, shared with the select face and the date field so a mixed row sits on one line to the pixel.
| Size | Specimen | Where |
|---|---|---|
| S.mk-ctl-s — 36px | Dense rows and filter rails. | |
| M.mk-input default — 44px | Forms. | |
| L.mk-ctl-l — 48px | A prominent single field, 16px type. |
States
| State | Specimen | What changes |
|---|---|---|
| Rest | The strong grey edge on every ground; the placeholder speaks in the quiet ink. | |
| Hover | The border warms to the accent — the engaged-field edge, shared with focus. | |
| Keyboard focus | The warm edge plus the 2px camel outline — every focus, not only the keyboard's. | |
| Filled | The value in full ink — a fact now, not a prompt. | |
| With help | A constraint, explained before the mistake. | .mk-field-help under the control, tied by
aria-describedby. |
| Invalid | What is wrong, in a sentence. | The error edge and .mk-field-error saying what is wrong —
aria-invalid="true" is the state. |
| Disabled | Cannot be used. Dimmed field, dead hover. | |
| Read-only | Cannot be changed — a different promise wearing a visibly different face: ordinary ink, no engagement edge. |
Text area
The multi-line form of the same input face, introduced after the one-line component's sizes and states are established. Use it for a note or a request as the guest wrote it — anything that must be read back as prose.
- One faceThe same
.mk-inputclass on a<textarea>— edge, radius, type and states are inherited from the input rather than restated. - Its own floor88px minimum instead of the control ladder — a multi-line field promises room for more than a line, so the S / M / L heights do not apply to it.
- Grows down only
resize: vertical— the agent may pull it taller for a long note, never sideways out of the form's measure. - Reads like proseLine height 1.5, the reading rhythm — a note is read back, not scanned.
Do and don't
Input
The label names the fact and stays visible while the agent types.
A placeholder posing as the label disappears at the first keystroke — the agent mid-form no longer knows what the half-filled field asks.
Text area
Give prose visible room and keep the fact named while the note grows.
A long note trapped in one line cannot be reviewed without scrolling through the field a fragment at a time.
Copy
- The label names the factLead guest name, sentence case, no colon. It answers what belongs here, never how the form works.
- Help states the constraintBefore the mistake, in the muted voice — not after it, shouting.
- The error is a sentenceWhat is wrong and what would be right — plain lowercase, no codes.
Accessibility
- One label, one controlThe label wraps or references its field, so pressing it focuses and reading it announces.
- Errors are wired
aria-invalid="true"plusaria-describedbypointing at the error's own element. - Native semanticsReal input types — date, number, tel — so the right keyboard arrives on touch.
- 44px floorEvery size at or above M is its own target; S rides rows that carry the floor for it. The field's width belongs to the form, not the component.
When to reach for something else
- SearchingUse Search — the magnifier-in-field face is the only legal search.
- Choosing from a listUse Dropdown; the input's shape promises free entry.
- A date or a rangeUse Date picker, which opens the shared calendar.
- A small bounded countUse Stepper.
Markup
<label class="mk-field"> <span class="mk-field-label">Field label</span> <input class="mk-input" type="text" placeholder="Placeholder"> <span class="mk-field-help">A constraint, explained before the mistake.</span> </label> <!-- invalid --> <input class="mk-input" type="text" aria-invalid="true" aria-describedby="err"> <span class="mk-field-error" id="err">What is wrong, in a sentence.</span> <!-- multi-line prose keeps the same component face --> <label class="mk-field"> <span class="mk-field-label">Guest request</span> <textarea class="mk-input" rows="4"></textarea> </label>