Input group

A Composed input row that joins one input with addons and buttons. The default puts the whole group behind a single shared border; .is-joined restores per-child borders with shaded endcap addons.

Examples

Input groups

$ USD
@
<div class="stack">
                <div class="input-group">
                    <span class="input-addon">
                        <svg
                            width="16"
                            height="16"
                            viewBox="0 0 24 24"
                            fill="none"
                            stroke="currentColor"
                            stroke-width="2"
                            stroke-linecap="round"
                            stroke-linejoin="round"
                            aria-hidden="true"
                        >
                            <circle cx="11" cy="11" r="8" />
                            <path d="m21 21-4.3-4.3" />
                        </svg>
                    </span>
                    <input type="search" class="input" placeholder="Search" />
                </div>

                <div class="input-group">
                    <span class="input-addon">$</span>
                    <input type="number" class="input" placeholder="0.00" />
                    <span class="input-addon">USD</span>
                </div>

                <div class="input-group">
                    <input type="email" class="input" placeholder="you@example.com" />
                    <button class="button" type="submit">Subscribe</button>
                </div>

                <div class="input-group">
                    <span class="input-addon">
                        <svg
                            width="16"
                            height="16"
                            viewBox="0 0 24 24"
                            fill="none"
                            stroke="currentColor"
                            stroke-width="2"
                            stroke-linecap="round"
                            stroke-linejoin="round"
                            aria-hidden="true"
                        >
                            <circle cx="11" cy="11" r="8" />
                            <path d="m21 21-4.3-4.3" />
                        </svg>
                    </span>
                    <input type="search" class="input" placeholder="Find a product" />
                    <button class="button" type="submit">Search</button>
                </div>

                <div class="input-group">
                    <span class="input-addon">@</span>
                    <input type="text" class="input" value="octetic" disabled />
                </div>
            </div>

Validation

$ USD

Amount must be greater than zero.

<div>
            <div class="flow flow-space-sm">
                <label for="ig-amount">Donation amount</label>
                <div class="input-group">
                    <span class="input-addon">$</span>
                    <input
                        id="ig-amount"
                        type="number"
                        class="input"
                        value="-50"
                        aria-invalid="true"
                        aria-describedby="ig-amount-err"
                    />
                    <span class="input-addon">USD</span>
                </div>
                <p id="ig-amount-err" class="text-danger text--1">
                    Amount must be greater than zero.
                </p>
            </div>
        </div>
    </div>

Classic shaded endcaps

https://
<div class="input-group is-joined">
            <span class="input-addon">https://</span>
            <input type="url" class="input" placeholder="example.com" />
        </div>

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-group

Classes

ClassKindDescription
.is-joinedvariantClassic shaded-endcap look with per-child borders

Slots

SlotDescription
.input-addonLabel, icon, or unit addon inside an input group

Related: Input

The universal form-control class. One class covers every input type; each type shares the input appearance (border, radius, surface, focus ring) and adds its own shape below.

Source: src/css/input.css

Applies to

.input, .input-addon, .input-group, input[type="checkbox"].input, input[type="radio"].input

Classes

ClassKindDescription
.is-smvariantSmaller text input with tighter padding
.is-lgvariantLarger text input with more padding

Selectors

SelectorDescription
input[type="file"].inputFile input; padded shell around a styled native selector button
textarea.inputMulti-line text; height comes from rows (or field-sizing), vertical resize only
select.inputNative select; appearance:none with a CSS-drawn chevron

Tokens

TokenDefaultDescription
--input-border-colorvar(--color-border-stronger)Border color shared across the input family
--input-border-widthvar(--border-width-default)Border width shared across the input family
--input-radiusvar(--radius-md)Border radius shared across the input family
--input-bgvar(--color-surface)Background color shared across the input family
--input-focus-colorvar(--color-focus)Focus ring color shared across the input family
--input-transitionvar(--transition-fast)Transition speed shared across the input family
--input-height2.25remBlock height for text inputs and select
--input-padding-blockvar(--ui-pad-block-compact)Block-axis inner padding for text inputs and select
--input-padding-inlinevar(--ui-pad-inline-tight)Inline-axis inner padding for text inputs and select
--input-font-sizevar(--ui-font-size-sm)Font size for text inputs and select
--input-line-heightvar(--leading-tight)Line height for text inputs and select
--input-chevron-colorvar(--color-text-muted)Color of the select dropdown chevron