Input Group
StableAn input with icons, text, buttons or keyboard hints attached — bordered, focused and validated as a single control.
Anatomy
- 1GroupOne bordered field that owns the focus halo, so the addons and the input read as a single control.
- 2Leading addonText or an icon before the input: a protocol, a currency, a search icon. Clicking it focuses the input.
- 3ControlThe input or textarea itself, borderless inside the group.
- 4Trailing addonA button, a unit or a keyboard hint after the input.
Installation
$ pnpm dlx shadcn@latest add https://www.prfct.dev/r/input-group.jsonUsage
import {
InputGroup,
InputGroupAddon,
InputGroupButton,
InputGroupInput,
InputGroupText,
} from "@/components/ui/input-group"<InputGroup>
<InputGroupAddon>
<SearchIcon />
</InputGroupAddon>
<InputGroupInput placeholder="Search…" />
</InputGroup>Inside a group, use InputGroupInput and InputGroupTextarea — never a plain Input. The group owns the border, fill, focus halo and invalid state; the inner control is deliberately bare.
Examples
Text addons
Prefixes and suffixes carry units and fixed parts of a value — a currency, a domain — so people type only what's variable. Wrap text in InputGroupText.
Buttons
InputGroupButton is a compact ghost Button sized to sit inside the field: copy a value, reveal a password, clear a query. Icon-only buttons need an aria-label; toggles like Show password also report aria-pressed.
Status
Addons can report what's happening to the value — checking availability with a Spinner, then confirming with an icon. Always repeat the status in text below the field; an icon alone isn't enough.
Checking availability…
ada.lovelace is available.
Composer
With InputGroupTextarea and a block-end addon, the group becomes a message composer: the field grows with the text while attachments, hints and the send action stay pinned below it.
Block addons
block-start addons sit above the control, full width — a file name above a code editor, a toolbar above a note. Add border-b to separate them.
Guidelines
When to use
- Units, prefixes and suffixes that are part of the value:
$,USD,.prfct.dev,https://. - Actions that operate on the value itself: copy, reveal, clear, submit a search.
- Signals about the value: a leading search icon, a validation status, a keyboard shortcut hint.
When not to use
- Actions that aren't about the value, like Save or Cancel — put a Button next to the field instead.
- More than two addons on one side. A crowded field is hard to scan and leaves little room to type.
- Multi-line rich editing with formatting — use a dedicated editor.
Keep addons honest
A leading icon should clarify what the field is for, not decorate it. If it's interactive, it must be an InputGroupButton with a label — a clickable-looking icon that does nothing is a trap.
Accessibility
- One control, one name. Label the
InputGroupInputwith aFieldLabelandhtmlFor/id, oraria-label. Addon text likeUSDis not part of the name — mention the unit in the label or description when it matters. - Grouping. The group and each addon render
role="group"; clicking an addon's empty space focuses the input. - Focus and state. The whole group shows the brand focus halo while its control has keyboard focus, and turns red when the control has
aria-invalid. - Buttons.
InputGroupButtonis a real button withtype="button"by default, so it never submits a form by accident. - Shortcuts. A
Kbdhint is visual only. Make the shortcut discoverable elsewhere too, such as in a tooltip or a help page.
| Key | Behavior |
|---|---|
Tab | Moves focus to the input, then to each button in the group. |
EnterSpace | Activates a focused InputGroupButton. |
API reference
InputGroup
Renders a <div role="group"> that draws the border, fill and focus state. Accepts all div props.
InputGroupAddon
Renders a <div role="group"> that holds icons, text, buttons or Kbd hints.
InputGroupButton
Renders a Button sized for the group. Accepts all Button props; size takes the group's own sizes, listed below.
InputGroupText
Renders a <span> for text and icons in muted-foreground.
InputGroupInput
Renders a borderless Base UI Input. Accepts all native input props.
InputGroupTextarea
Renders a borderless <textarea> that grows with its content. Accepts all native textarea props.