Input Group
An input with attached addons – icons, text, buttons or keyboard hints – inline or as block rows. The whole group focuses as one control.
Playground
<InputGroup>
<InputGroupAddon align="inline-start">
<InputGroupText>
<Search />
</InputGroupText>
</InputGroupAddon>
<InputGroupInput placeholder="Search..." />
</InputGroup>Preview
Wrap an InputGroupInput with addons aligned inline-start or inline-end; clicking an addon focuses the input.
<InputGroup>
<InputGroupAddon align="inline-start">
<InputGroupText>
<Search />
</InputGroupText>
</InputGroupAddon>
<InputGroupInput placeholder="Search..." />
</InputGroup>Installation
npx shadcn@latest add https://espresso-base-ui.vercel.app/r/input-group.jsonUsage
import {
InputGroup,
InputGroupAddon,
InputGroupButton,
InputGroupInput,
InputGroupText,
InputGroupTextarea,
} from "@/components/ui/input-group"<InputGroup variant="subtle" size="sm">
<InputGroupAddon align="inline-start">
<InputGroupText>https://</InputGroupText>
</InputGroupAddon>
<InputGroupInput placeholder="example.com" />
</InputGroup>Variants and sizes
The group takes the same variant and size scales as Input – outline, subtle and ghost across xs to lg – and sizes the inner control to match.
<InputGroup variant="outline" size="md">
<InputGroupAddon align="inline-start">
<InputGroupText>
<Search />
</InputGroupText>
</InputGroupAddon>
<InputGroupInput placeholder="Outline (md)" />
</InputGroup>
<InputGroup variant="subtle" size="sm">
<InputGroupAddon align="inline-start">
<InputGroupText>
<Search />
</InputGroupText>
</InputGroupAddon>
<InputGroupInput placeholder="Subtle (sm)" />
</InputGroup>
<InputGroup variant="ghost" size="lg">
<InputGroupAddon align="inline-start">
<InputGroupText>
<Search />
</InputGroupText>
</InputGroupAddon>
<InputGroupInput placeholder="Ghost (lg)" />
</InputGroup>Block alignment and textarea
block-start and block-end addons become full-width rows above or below the control, and the group switches to a column – swap in InputGroupTextarea for multi-line composers with an action row.
<InputGroup>
<InputGroupAddon align="block-start">
<InputGroupText>Label on top</InputGroupText>
</InputGroupAddon>
<InputGroupInput placeholder="Enter value..." />
</InputGroup>
<InputGroup>
<InputGroupTextarea placeholder="Write a message..." rows={3} />
<InputGroupAddon align="block-end">
<InputGroupButton size="xs">Send</InputGroupButton>
</InputGroupAddon>
</InputGroup>States
Disable the inner control and the whole group follows; set data-valid, data-invalid or data-filled on the group to force those surfaces.
<InputGroup>
<InputGroupAddon align="inline-start">
<InputGroupText>
<Search />
</InputGroupText>
</InputGroupAddon>
<InputGroupInput placeholder="Disabled" disabled />
</InputGroup>
<InputGroup data-invalid="true">
<InputGroupAddon align="inline-start">
<InputGroupText>
<Search />
</InputGroupText>
</InputGroupAddon>
<InputGroupInput defaultValue="Invalid" />
</InputGroup>
<InputGroup data-valid="true">
<InputGroupAddon align="inline-start">
<InputGroupText>
<Search />
</InputGroupText>
</InputGroupAddon>
<InputGroupInput defaultValue="Valid" />
</InputGroup>API reference
The group root carries the visual props; addons carry alignment; the input and textarea are restyled versions of Input and Textarea that drop their own borders and shadows so the group reads as one field.
InputGroup
| Prop | Type | Default | Description |
|---|---|---|---|
| variant | "outline" | "subtle" | "ghost" | "outline" | Surface of the whole group – shadow ring, filled secondary background, or transparent until interaction. |
| size | "xs" | "sm" | "md" | "lg" | "md" | Group height (24 / 28 / 32 / 40px); the inner control inherits matching height, padding and text size via data-size. |
InputGroupAddon
| Prop | Type | Default | Description |
|---|---|---|---|
| align | "inline-start" | "inline-end" | "block-start" | "block-end" | "inline-start" | Placement – inline at either end of the control, or as a full-width row above (block-start) / below (block-end), which switches the group to a column layout. |
InputGroupButton
| Prop | Type | Default | Description |
|---|---|---|---|
| variant | Button variant | "ghost" | Forwarded to the underlying Button. |
| size | "xs" | "sm" | "icon-xs" | "icon-sm" | "xs" | Compact sizes tuned for in-group use, including square icon-only options. |
| type | "button" | "submit" | "reset" | "button" | Button type – defaults to button to avoid accidental form submits. |
| Component | Description |
|---|---|
| InputGroup | Group root with role="group" (data-slot="input-group"); reflects data-variant and data-size and reacts to data-filled / data-invalid / data-valid. |
| InputGroupAddon | Addon container (data-slot="input-group-addon", data-align). Clicking it focuses the input unless a button was clicked. |
| InputGroupText | Muted inline text or icon span for static prefixes and suffixes. |
| InputGroupButton | Ghost Button preconfigured with compact in-group sizing. |
| InputGroupInput | Borderless Input wired to the group (data-slot="input-group-control"); accepts all Input props except size. |
| InputGroupTextarea | Borderless Textarea wired to the group (data-slot="input-group-control") for multi-line layouts. |
Accessibility & styling hooks
The root and each addon render role="group", and the focus ring is drawn on the group when the inner data-slot="input-group-control" receives focus – so one visual control matches one focus target. Setting aria-invalid on the control adds a destructive ring to the whole group; label the control itself via htmlFor/id or a wrapping Field. The inputGroupVariants cva helper is also exported for custom composite fields.