Input
Input — text entry.
Examples
<div class="field">
<label class="field-label" for="demo-name">Full name</label>
<input class="input" id="demo-name" name="name" type="text" autocomplete="name" />
</div>
<div class="field">
<label class="field-label" for="demo-find">Search</label>
<input class="input" id="demo-find" name="q" type="search" placeholder="Filter…" />
</div>
<div class="field">
<label class="field-label" for="demo-note">Message</label>
<textarea class="input" id="demo-note" name="message" rows="3"></textarea>
</div>One class for every type. All three are shown at the same size on purpose: mixing sizes in one example makes the shorter control look like a rendering fault rather than a choice, so the sizes get an example of their own below.
The textarea grows with its content where field-sizing is supported, and stays a plain resizable textarea where it is not.
<div class="field">
<label class="field-label" for="size-sm">Small — 32px</label>
<input class="input input-sm" id="size-sm" name="sm" type="text" value="Dense tables and toolbars" />
</div>
<div class="field">
<label class="field-label" for="size-md">Default — 40px</label>
<input class="input" id="size-md" name="md" type="text" value="Everything else" />
</div>
<div class="field">
<label class="field-label" for="size-lg">Large — 48px</label>
<input class="input input-lg" id="size-lg" name="lg" type="text" value="A single prominent field" />
</div>The default shares its 2.5rem floor with .btn, so a field and a button in the same row line up and every target stays reachable for an imprecise pointer.
.input-sm goes below that floor deliberately: it is for a control inside a toolbar or a table row, where the surrounding density is the point and the spacing exception applies.
Tokens 24
Level 2, declared on .input itself. Set any of them on that selector to restyle this component without touching the skin.
| Token | Default |
|---|---|
| --input-max-block-size | 24rem |
| --input-min-block-size | 4.5rem |
| --input-datetime-indicator-hover-bg | var(--color-surface-raised) |
| --input-datetime-indicator-radius | var(--radius-sm) |
| --input-datetime-segment-color | var(--color-on-surface) |
| --input-datetime-segment-focus-bg | var(--color-primary) |
| --input-datetime-segment-focus-color | var(--color-on-primary) |
| --input-datetime-segment-padding | var(--space-px) |
| --input-datetime-segment-radius | var(--radius-sm) |
| --input-datetime-separator-color | var(--color-on-surface-muted) |
| --input-bg | var(--color-surface-sunken) |
| --input-border-color | var(--color-border-strong) |
| --input-border-width | var(--border-width) |
| --input-color | var(--color-on-surface) |
| --input-padding-block | var(--space-2) |
| --input-placeholder-color | var(--color-on-surface-muted) |
| --input-radius | var(--radius-field) |
| --input-caret-color | var(--color-primary) |
| --input-font-family | var(--font-secondary) |
| --input-font-size | var(--font-size-sm) |
| --input-hover-border-color | var(--color-border-strong) |
| --input-invalid-border-color | var(--color-danger) |
| --input-list-icon | url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E") |
| --input-min-size | var(--target-size) |
Variants and states
Variants
.input-lg.input-sm
Inside it
.input-password
State it reads
Read from the platform, never mirrored into a class that could disagree with it.
:disabled:focus:hover:user-invalid[readonly]data-legacy
Before you ship it
What you have to do 1 requirements
- Give every input a real
<label>. Aplaceholderis not a label: it disappears the moment typing starts, it is not reliably announced, and its contrast is deliberately low. Where the error text lives, see field.css — the association isaria-describedbyon this element.
src/css/components/input.css · npx mostlycss add input