Examples
Basic usage
<form class="stack">
<div class="stack is-tight">
<label for="f-email">Email</label>
<input
id="f-email"
type="email"
class="input"
placeholder="you@example.com"
required
/>
</div>
<div class="stack is-tight">
<label for="f-message">Message</label>
<textarea id="f-message" class="input" rows="3"></textarea>
</div>
<button class="button" type="submit">Send</button>
</form>
Size
<div class="cluster is-tight">
<input type="text" class="input is-sm" placeholder="Small" />
<input type="text" class="input" placeholder="Default" />
<input type="text" class="input is-lg" placeholder="Large" />
</div>
State
Letters, numbers, and underscores only.
Shown on your public profile.
<div class="stack">
<div>
<div class="stack is-tight measure-narrow">
<label for="f-username">Username</label>
<input
id="f-username"
type="text"
class="input"
value="nope!"
aria-invalid="true"
aria-describedby="f-username-err"
/>
<p id="f-username-err" class="text-danger text--1">
Letters, numbers, and underscores only.
</p>
</div>
</div>
<div class="stack is-tight">
<label for="f-locked">Account ID</label>
<input id="f-locked" type="text" class="input" value="ACC-0042" disabled />
</div>
</div>
<div class="stack">
<div class="stack is-tight">
<label for="f-readonly">Account ID</label>
<input id="f-readonly" type="text" class="input" value="ACC-0042" readonly />
</div>
<div>
<div class="stack is-tight">
<label for="f-helped">Display name</label>
<input
id="f-helped"
type="text"
class="input"
value="octetic"
aria-describedby="f-helped-help"
/>
<p id="f-helped-help" class="text-muted text--1">
Shown on your public profile.
</p>
</div>
</div>
</div>
</div>
Native types
<div class="stack is-snug">
<input type="email" class="input" placeholder="you@example.com" />
<input type="password" class="input" placeholder="Password" />
<input type="search" class="input" placeholder="Search..." />
<input type="tel" class="input" placeholder="(555) 123-4567" />
<input type="url" class="input" placeholder="https://example.com" />
<input type="number" class="input" placeholder="42" />
<input type="date" class="input" />
<input type="time" class="input" />
</div>
Textarea
<div class="stack">
<textarea class="input" rows="4" placeholder="Fixed rows"></textarea>
<div style="block-size: 12rem">
<textarea
class="input"
style="inline-size: 100%; block-size: 100%"
placeholder="Fill container"
></textarea>
</div>
<textarea
class="input"
style="field-sizing: content; min-block-size: 2.25rem"
placeholder="Grow with content"
></textarea>
</div>
Select
<div class="stack is-tight">
<label for="f-role">Role</label>
<select id="f-role" class="input">
<option>Admin</option>
<option>Editor</option>
<option>Viewer</option>
</select>
</div>
File
<div class="stack is-tight">
<label for="f-avatar">Avatar</label>
<input id="f-avatar" type="file" class="input" accept="image/*" />
</div>
Stacked (canonical)
<form class="stack">
<div class="stack is-tight">
<label for="signin-email">Email</label>
<input
id="signin-email"
type="email"
class="input"
required
autocomplete="username"
/>
</div>
<div class="stack is-tight">
<label for="signin-password">Password</label>
<input
id="signin-password"
type="password"
class="input"
required
autocomplete="current-password"
/>
</div>
<label class="cluster is-tight">
<input type="checkbox" name="remember" class="input" /> Remember me on this device
</label>
<button class="button" type="submit">Sign in</button>
</form>
Horizontal
<form class="cluster is-snug" role="search">
<label for="quick-search">Search products</label>
<input
id="quick-search"
style="flex: 1"
type="search"
class="input"
placeholder="Widget, gadget, ..."
autocomplete="off"
/>
<button class="button" type="submit">Go</button>
</form>
Multi-column fields
<form class="stack">
<div class="stack is-tight">
<label for="addr-street">Street address</label>
<input
id="addr-street"
type="text"
class="input"
autocomplete="street-address"
/>
</div>
<div class="grid" style="--grid-min: 12rem">
<div class="stack is-tight">
<label for="addr-city">City</label>
<input
id="addr-city"
type="text"
class="input"
autocomplete="address-level2"
/>
</div>
<div class="stack is-tight">
<label for="addr-state">State</label>
<input
id="addr-state"
type="text"
class="input"
autocomplete="address-level1"
/>
</div>
<div class="stack is-tight">
<label for="addr-zip">ZIP</label>
<input
id="addr-zip"
type="text"
inputmode="numeric"
class="input"
autocomplete="postal-code"
/>
</div>
</div>
<div class="cluster is-end">
<button class="button is-ghost" type="button">Cancel</button>
<button class="button" type="submit">Save address</button>
</div>
</form>
Sectioned with fieldsets
<form class="stack">
<fieldset class="stack is-tight">
<legend class="text-subtle text-semibold">Notifications</legend>
<label class="cluster is-tight">
<input type="checkbox" checked class="input" /> Product updates
</label>
<label class="cluster is-tight">
<input type="checkbox" class="input" /> Weekly digest
</label>
<label class="cluster is-tight">
<input type="checkbox" checked class="input" /> Security alerts
</label>
</fieldset>
<fieldset class="stack is-tight">
<legend class="text-subtle text-semibold">Profile visibility</legend>
<label class="cluster is-tight">
<input type="radio" name="visibility" value="public" checked class="input" />
Public (anyone can find your profile)
</label>
<label class="cluster is-tight">
<input type="radio" name="visibility" value="unlisted" class="input" /> Unlisted
(direct link required)
</label>
<label class="cluster is-tight">
<input type="radio" name="visibility" value="private" class="input" /> Private
(only you)
</label>
</fieldset>
<div class="cluster is-between">
<button class="button is-ghost" type="button">Cancel</button>
<button class="button" type="submit">Save settings</button>
</div>
</form>
Source comments
Input family -- text inputs, textarea, select, file, checkbox,
radio, and input-group. Atoms share a common chrome token set
(--input-border-color, --input-border-width, --input-radius,
--input-bg, --input-focus-color, --input-transition) so one override
on any ancestor retones the whole family.
Markup:
<form class="stack">
<div class="stack is-tight">
<label for="email">Email</label>
<input id="email" type="email" class="input" required>
</div>
<button class="button" type="submit">Submit</button>
</form>
Labeled checkbox/radio: <label class="cluster is-tight">
(Flex's anon-item rule means no span wrapper around text.)
<fieldset> + <legend> for groups; bare with base.css defaults.
Design notes:
- Validation states paint borders; error COPY is author-
responsible (<p class="text-danger"> adjacent, or page-level
<div class="alert is-danger" role="alert">). The automatic
paint is gated by :user-invalid -- it matches only after the
user has interacted with the control, so an empty required
field does not render invalid on page load. Engines without
:user-invalid keep the aria-invalid paint (the author-driven
one) and simply skip the automatic one; graceful degradation,
no feature query (P-stance on modern CSS).
- A required field inside the field-unit stack (label directly
before the control) picks up a CSS-drawn marker on its label --
form.css owns that rule. The full label / help / error
convention lives in the patterns section's field unit page.
- Checkbox/radio/range use appearance:none custom chrome for
visual parity with .input in dense forms. @media (forced-
colors: active) reverts to native rendering for all three.
- Select chevron is a pure-CSS two-gradient V per P8. Border-
rotate chevron (details, sidebar-nav) needs a pseudo, and
<select> doesn't accept pseudos in evergreen browsers
without appearance: base-select.
- .input uses :focus (not :focus-visible) because text entry
needs the ring on click for caret visibility. Checkbox and
radio use :focus-visible (no caret).
- .input-group default: group owns border/bg; children are
transparent. .is-joined reinstates per-child borders for
the classic shaded-endcap look.
Reference
Source: src/css/input.css
Applies to
.input, .input-addon, .input-group, input[type="checkbox"].input, input[type="radio"].input
Classes
| Class | Kind | Description |
|---|---|---|
.is-sm | variant | Smaller text input with tighter padding |
.is-lg | variant | Larger text input with more padding |
Selectors
| Selector | Description |
|---|---|
input[type="file"].input | File input; padded shell around a styled native selector button |
textarea.input | Multi-line text; height comes from rows (or field-sizing), vertical resize only |
select.input | Native select; appearance:none with a CSS-drawn chevron |
Tokens
| Token | Default | Description |
|---|---|---|
--input-border-color | var(--color-border-stronger) | Border color shared across the input family |
--input-border-width | var(--border-width-default) | Border width shared across the input family |
--input-radius | var(--radius-md) | Border radius shared across the input family |
--input-bg | var(--color-surface) | Background color shared across the input family |
--input-focus-color | var(--color-focus) | Focus ring color shared across the input family |
--input-transition | var(--transition-fast) | Transition speed shared across the input family |
--input-height | 2.25rem | Block height for text inputs and select |
--input-padding-block | var(--ui-pad-block-compact) | Block-axis inner padding for text inputs and select |
--input-padding-inline | var(--ui-pad-inline-tight) | Inline-axis inner padding for text inputs and select |
--input-font-size | var(--ui-font-size-sm) | Font size for text inputs and select |
--input-line-height | var(--leading-tight) | Line height for text inputs and select |
--input-chevron-color | var(--color-text-muted) | Color of the select dropdown chevron |