Input group
An input or textarea with addons inside its border: icons, units, keycaps and small buttons. The group is the pill and owns the focus ring, so the whole thing reads as one field. Source: src/components/ui/input-group.tsx.
Addons
An addon is inline-start by default. Icons are 16px and muted; InputGroupText carries units. Click an icon and the input takes focus.
Buttons
InputGroupButton is a ghost Button scaled to fit (24px). Use icon-xs with an aria-label for a lone icon, xs for a word.
Show or hide a secret
Copy a value
Textarea and block addons
Put an InputGroupTextarea inside and add a block-end addon: the group becomes a 12px-corner column with a toolbar under the text. This is the composer's shape.
Type, then press the arrow or Cmd/Ctrl+Enter.
States
The group mirrors its control: focus rings the whole shell, aria-invalid on the control turns it destructive, a disabled control fades the group to 50%. The error text is yours; there is no Field primitive.
Handles can't contain spaces.
Props
Six parts. None of them has a variant of its own beyond what is listed.
| Prop | Type | Default | Description |
|---|---|---|---|
| InputGroup | ComponentProps<"div"> | — | The shell: role="group", a 32px pill with the input outline. It reads focus, disabled and aria-invalid from its control with :has(), so you style nothing. |
| InputGroupAddon align | "inline-start" | "inline-end" | "block-start" | "block-end" | "inline-start" | Where the addon sits. block-* stacks it above or below and turns the shell into a 12px-corner column. Clicking an addon focuses the group's input. |
| InputGroupButton size | "xs" | "sm" | "icon-xs" | "icon-sm" | "xs" | A Button (default variant="ghost", type="button") sized to sit inside the field. All other Button props pass through. |
| InputGroupInput | ComponentProps<"input"> | — | An Input with its own border and ring removed; marked data-slot="input-group-control". |
| InputGroupTextarea | ComponentProps<"textarea"> | — | A Textarea without its box and with resize off. The shell grows with it. |
| InputGroupText | ComponentProps<"span"> | — | Muted inline text for a unit, a prefix or a domain. |
Best practices
When to use
- When something belongs inside the field: a search icon, a currency, a domain suffix, a reveal or copy button.
- A plain field with no addon is an Input; don't wrap it in a group for nothing.
Behavior
- Keep addons to one or two per side. A row of buttons is a toolbar under the field (block-end).
- Don't put a submit button inside the group of a single-field form if Enter already submits; it doubles the action.
- The shell is a pill (rounded-full); it changes to 12px corners only for textareas and block addons.
Accessibility
- The control needs its own label: a Label with htmlFor, or an aria-label. The addon icon is decorative and aria-hidden.
- Icon-only InputGroupButtons take an aria-label; a toggle (show/hide) also takes aria-pressed.
- Announce transient results such as Copied in an aria-live region.
Content
- Units go in InputGroupText, not in the placeholder, so they stay visible after typing.