Input

input.input[type="text"]

Input — text entry.

Examples

The three shapes

View “The three shapes” as
<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.

Sizes

View “Sizes” as
<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.

Level 2 tokens declared by input
TokenDefault
--input-max-block-size24rem
--input-min-block-size4.5rem
--input-datetime-indicator-hover-bgvar(--color-surface-raised)
--input-datetime-indicator-radiusvar(--radius-sm)
--input-datetime-segment-colorvar(--color-on-surface)
--input-datetime-segment-focus-bgvar(--color-primary)
--input-datetime-segment-focus-colorvar(--color-on-primary)
--input-datetime-segment-paddingvar(--space-px)
--input-datetime-segment-radiusvar(--radius-sm)
--input-datetime-separator-colorvar(--color-on-surface-muted)
--input-bgvar(--color-surface-sunken)
--input-border-colorvar(--color-border-strong)
--input-border-widthvar(--border-width)
--input-colorvar(--color-on-surface)
--input-padding-blockvar(--space-2)
--input-placeholder-colorvar(--color-on-surface-muted)
--input-radiusvar(--radius-field)
--input-caret-colorvar(--color-primary)
--input-font-familyvar(--font-secondary)
--input-font-sizevar(--font-size-sm)
--input-hover-border-colorvar(--color-border-strong)
--input-invalid-border-colorvar(--color-danger)
--input-list-iconurl("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-sizevar(--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

  1. Give every input a real <label>. A placeholder is 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 is aria-describedby on this element.

src/css/components/input.css · npx mostlycss add input