Skip to content

Input group

Input with company — a prefix, a suffix, a leading icon, a button — inside one box that behaves like Input.

Beta · Forms · packages/css/src/components/input-group.css

.pui-input-group · __icon __prefix __control __suffix __button · size --small --large · --error --disabled · ground --on-dark. The nested button sits at the 4 px inset, radius 4.

Input group — every size and every stateOpen in the workshop

Sizes across, states down.

  • Input’s properties — Placeholder, Value, Has value, Has placeholder, Has icon leading, Icon leading — plus Prefix / Has prefix, Suffix / Has suffix (text/subtle at the text’s size) and Has button; the Button is exposed and stretches to the box
  • Three sizes: small has no button (no 20px Button exists); medium takes Button small; large takes Button medium
  • Five states on the box, Input’s: hover border/strong, focus and error with the ring, disabled at .5 with its button
  • One box, one border: never two bordered controls side by side pretending to be one (that is a row of Input + Button at space/8)
  • The nesting rule: a control inside a radius-8 box takes radius 4 and an equal inset on every side — the inset is the size step (36 − 28 = 8, so 4 each side), never the text padding
  • Ground on-dark — the same box on surface/inverse, the footer’s email field: the wash color/alpha/white-8, the line nav/item/bg-active, the ink nav/item/fg-active, the placeholder nav/section/fg, and the Button in it turned over — text/on-inverse under text/default. Hover, focus and error are the box’s own. Drawn at medium, the footer’s size; large takes the same colours

Use when an input needs a unit, a scheme or a domain beside its text (prefix / suffix), an icon in front of it, or one action attached to it — subscribe, search, copy, apply a code.

Do not use when the field stands alone (that is Input, in a Field); when two or more actions belong to the input (that is a toolbar); for a select beside an input (Select stays its own control).

Relates to Input, Field, Button, Icon button, Select, Combobox.

Anti-patterns a button of the box’s own height (it sits one size below, inside the padding) · a nested button at the box’s own radius 8 · a right inset larger than the top and bottom · a second border around the inner text · a prefix that repeats the label · a suffix used as a placeholder · a fill changed on the instance.

Keywords: input group, addon, prefix, suffix, search, subscribe, input with button

Figma — page Input group: Input group (20 variants)

shadcn: input-group

The class, the parts, and nothing that is not in the package. The same block opens input-group.css.

<label class="pui-input-group">
<span class="pui-icon pui-input-group__icon">…search…</span>
<span class="pui-input-group__prefix">https://</span>
<input class="pui-input-group__control" type="text" placeholder="Your email">
<span class="pui-input-group__suffix">.com</span>
<button class="pui-button pui-button--small pui-input-group__button">Subscribe</button>
</label>
What it is Note
Size --small 28 (12 px, no button — no 20 px Button exists) · (none) medium 36 (button small) · --large 44 (16 px, button medium) —
State :hover · :focus-within · error = --error or :has([aria-invalid=“true”]) (+ the error ring when focused) · disabled = --disabled or :has(:disabled) —
Ground (none) light · --on-dark — the same box on surface/inverse (the footer’s email field, request 33): the wash color/alpha/white-8, the line nav/item/bg-active, the ink nav/item/fg-active, the placeholder nav/section/fg, and the Button in it turned over — text/on-inverse under text/default, with the inset ring —
Parts __icon (16, text/muted) · __prefix / __suffix (the caption ink, the text’s size) · __control · __button —

Rule — one box, one border — never two bordered controls pretending to be one; the nested button takes radius 4 and the 4 px inset, never the text padding.

Every number here is measured on the rendered component: contrast (npm run contrast:render), the focus ring (npm run focus) and the keyboard (npm run keyboard). The floors are principle 12’s.

ink on ground reads floor the matrix calls it
#544d4d on #ffffff 8.24 4.5 text.muted on surface.page (promised) ok
#0b0202 on #ffffff 20.51 4.5 text.default on surface.page (promised) ok
#ffffff on #0b0202 20.51 4.5 Primary button label (promised) ok

3 distinct pair(s) rendered, 0 that axe calls a violation.

primitive on the indicator over the change
Input group surface/page shadow #6a66e4 2 px #ffffff 4.53 ok
Input group surface/card shadow #6a66e4 2 px #f2f2f7 4.06 ok
Input group surface/sunken shadow #6a66e4 2 px #f2f2f2 4.05 ok

15 of 15 focus stop(s) in this block meet WCAG 2.4.13 on screen — the same crop screenshotted focused and unfocused, and the difference measured.

Nothing in this component claims an ARIA role with a keyboard contract; its controls are ordinary ones and the browser already gives them their keys.

Tab order across the whole library is document order over 344 stops, and Shift+Tab is its exact reverse — no keyboard trap anywhere (WCAG 2.1.2).

Pepper UI v1.5.0

The Mobupps design system. 386 tokens, 88 components, 65 pages in the workshop — every page of this site generated from the repository, so nothing here is typed twice.