Input Group

Joins several controls, a field, a Select, a static affix, a small icon-only action, into one seamless segmented shell. The group owns the border and focus ring; each segment goes chromeless and melts in.

$

Installation#

# One-time setup (tokens + lib helpers)npx koalaui-cli@latest init# Add this component (its dependencies come along)npx koalaui-cli@latest add input-group

Usage#

usage.tsxTSX
import { InputGroup, InputGroupAddon } from "@/components/ui/input-group"import { InputRoot, InputField } from "@/components/ui/input"export function Example() {  return (    <InputGroup>      <InputGroupAddon>https://</InputGroupAddon>      <InputRoot>        <InputField placeholder="yourcompany" />      </InputRoot>      <InputGroupAddon>.com</InputGroupAddon>    </InputGroup>  )}

When to reach for it#

An Input already handles adornments inside a single field - a leading icon (InputPrefix), a divided label (InputPrefixLabel), a trailing icon button (InputSuffixButton). Reach for InputGroup only when you need to join several distinct controls - a Select, another field, a static affix - into one unit. One shell, one focus ring, one set of rounded corners.

A prominent text action - Subscribe, Invite, Search - does not belong inside the shell. Crammed in, it reads as a button trapped in a field. Keep it a detached Button beside the group instead (see below). Only a small icon-only action may melt in.

Pairing with an action#

Do not fuse a big text button into the field. Drop the group (or a plain InputRoot) and the Button into one flex row (items-stretch gap-2) at the same size: the field flexes, the button caps the row from outside, and the heights line up on their own. It reads as a real button, not a segment.

With a Select#

Drop a real Select in as a segment and it melts into the shell - its own border, ring, and background are stripped while its menu, keyboard nav, and ARIA stay intact. The field flexes to fill the row. The Invite action, being a text button, stays detached beside the group - same rule as the newsletter, one step richer.

Text affixes#

InputGroupAddon is a static, non-interactive segment for a unit, protocol, or symbol. It shares the shell background and reads as a muted label, on either side of the field.

https://
.com
@

Icon-only actions can melt in#

The one action that may live inside the shell is a small icon-only button - copy, clear, a submit arrow. With no label to crowd the field, it sits flush as a fused segment: it keeps its fill and hover but drops its own radius, ring, and press-scale. Use iconOnly and give it an aria-label.

koala.dev/

Sizes#

The size prop sets the shell height (sm 32, md 36, lg 40px) and the affix scale. Give the inner controls - and the detached Button - the matching size so every part lines up.

States#

hasError paints the whole shell red and turns the focus ring destructive; disabled dims and locks the row. Inside a Field, both cascade automatically. For form semantics, also disable the inner control so it is excluded from submission.

@
https://
.com

API reference#

PropTypeDefaultDescription
size"sm" | "md" | "lg""md"Shell height + affix sizing. Match it on the inner controls.
hasErrorboolean-Error styling. Cascades from a surrounding Field.
disabledboolean-Dim and lock the shell. Cascades from a surrounding Field.
...divPropsComponentProps<"div">-Forwarded to the shell. className merges last.

InputGroupAddon is a plain span segment and accepts every native span prop plus className.

FAQ#

Input already covers adornments inside one field: a leading icon (InputPrefix), a divided label (InputPrefixLabel), a trailing icon button (InputSuffixButton). Use InputGroup only when you are joining several distinct controls - a Select, another field, a static affix - into one shell. If everything lives in a single field, you do not need InputGroup.