Input Group
Adds icons, text, buttons or keyboard hints before or after an input or textarea, so extra information and actions sit inside the same control.
Powered by
Installation
npx shadcn@latest add @redpanda/input-grouppnpm dlx shadcn@latest add @redpanda/input-groupyarn dlx shadcn@latest add @redpanda/input-groupbunx shadcn@latest add @redpanda/input-groupnubx shadcn@latest add @redpanda/input-groupaube dlx shadcn@latest add @redpanda/input-groupWhen to use
Use this decision tree to determine when to use the Input Group component:
Usage
import { InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput, InputGroupText, InputGroupTextarea,} from '@/components/ui/input-group';<InputGroup> <InputGroupInput placeholder="Search..." /> <InputGroupAddon> <SearchIcon /> </InputGroupAddon> <InputGroupAddon align="inline-end"> <InputGroupButton>Search</InputGroupButton> </InputGroupAddon></InputGroup>Anatomy
The InputGroup component enhances inputs with inline addons. Here’s how the components work together:
<InputGroup> {/* Container with unified focus state */} <InputGroupAddon {/* Addon positioned at inline-start */} align="inline-start"> <SearchIcon /> {/* Icon, text, or button */} </InputGroupAddon> <InputGroupInput /> {/* Styled input (replaces Input) */} <InputGroupAddon {/* Addon positioned at inline-end */} align="inline-end"> <InputGroupButton> {/* Button in addon */} Search </InputGroupButton> </InputGroupAddon></InputGroup>Layout Structure
- InputGroup: Root container with
role="group"and unified focus ring - InputGroupInput: Replacement for
<Input />with group-specific styles - InputGroupTextarea: Replacement for
<Textarea />with group-specific styles - InputGroupAddon: Container for icons, text, or buttons alongside the input
- InputGroupButton: Styled button optimized for input groups (smaller sizes)
- InputGroupText: Text content that can be displayed in addons
Use shape="pill" on InputGroup for a fully rounded URL field. Its actions separately support the inherited
InputGroupButton shape="pill" contract; no local radius variables or rounded-class overrides are needed.
For textarea chrome, use separator on a block-start or block-end addon. The addon owns the adjacent border
and its padding. Inline addons do not accept a separator. Use a semantic <code> inside InputGroupText for a
filename rather than overriding the text primitive’s typography.
Place a popover trigger directly on the native InputGroupButton, not on an addon wrapping that button.
Information-only icons use a named Popover, with optional openOnHover, so keyboard and touch users can open
the content. Tooltips are only supplementary visual labels for independently named actions. Stateful favorites
expose aria-pressed on that native action.
Alignment Options
InputGroupAddon supports four alignment positions via the align prop:
- inline-start (default): Left side of input (or right in RTL)
- inline-end: Right side of input (or left in RTL)
- block-start: Top of textarea
- block-end: Bottom of textarea
Typical Usage Patterns
// Input with leading icon<InputGroup> <InputGroupAddon> <SearchIcon /> </InputGroupAddon> <InputGroupInput placeholder="Search..." /></InputGroup>
// Input with trailing button<InputGroup> <InputGroupInput placeholder="Enter email..." /> <InputGroupAddon align="inline-end"> <InputGroupButton>Subscribe</InputGroupButton> </InputGroupAddon></InputGroup>
// Input with both sides<InputGroup> <InputGroupAddon> <DollarIcon /> </InputGroupAddon> <InputGroupInput placeholder="0.00" /> <InputGroupAddon align="inline-end"> <InputGroupText>USD</InputGroupText> </InputGroupAddon></InputGroup>
// Textarea with button at bottom<InputGroup> <InputGroupTextarea placeholder="Write a message..." /> <InputGroupAddon align="block-end"> <InputGroupButton size="sm">Send</InputGroupButton> </InputGroupAddon></InputGroup>
// Input with loading state<InputGroup> <InputGroupInput placeholder="Searching..." /> <InputGroupAddon align="inline-end"> <Spinner /> </InputGroupAddon></InputGroup>
// Input with keyboard shortcut<InputGroup> <InputGroupInput placeholder="Search..." /> <InputGroupAddon align="inline-end"> <Kbd>⌘K</Kbd> </InputGroupAddon></InputGroup>Examples
Icon
Text
Display additional text information alongside inputs.
InputGroupText owns its standard typography and subtle text color. The text example uses associated static message guidance, not a remaining-character count, and does not impose a character limit. Use the component’s addon/input spacing rather than local input padding overrides.
Button
Add buttons to perform actions within the input group.
Information popovers
Information controls open accessible popovers by keyboard or touch, with optional hover access. Give each popup a title and description. Keep essential password requirements visible and associated with the input even while the popup is closed; this example also sets the native eight-character minimum. The email and API-key examples do not submit or verify credentials.
Textarea
Input groups also work with textarea components. Use block-start or block-end for alignment.
The textarea example edits a local draft. Reset restores its sample, and Copy copies the current value without submitting an enclosing form. Copy failures remain visible without discarding the draft; it does not execute code.
Spinner
Show loading indicators while processing input.
Label
Add labels within input groups to improve accessibility.
Dropdown
Pair input groups with dropdown menus for complex interactions.
Button Group
Wrap input groups with button groups to create prefixes and suffixes.
Custom Input
Custom controls that render a native input or textarea element get group focus state handling automatically. Add a data-slot attribute and aria-invalid to opt in to the group error state styling.
No style is applied to the custom input. Apply your own styles using the className prop.
'use client';
import TextareaAutosize from 'react-textarea-autosize';
import { InputGroup, InputGroupAddon, InputGroupButton } from '@/components/ui/input-group';
export function InputGroupCustom() { return ( <div className="grid w-full max-w-sm gap-6"> <InputGroup> <TextareaAutosize data-slot="input-group-control" className="flex field-sizing-content min-h-16 w-full resize-none rounded-md bg-transparent px-3 py-2.5 text-base transition-[color,box-shadow] outline-none md:text-sm" placeholder="Autoresize textarea..." /> <InputGroupAddon align="block-end"> <InputGroupButton className="ml-auto" size="sm"> Submit </InputGroupButton> </InputGroupAddon> </InputGroup> </div> );}import { InputGroup, InputGroupAddon } from '@/component/ui/input-group';import TextareaAutosize from 'react-textarea-autosize';
export function InputGroupCustom() { return ( <InputGroup> <TextareaAutosize data-slot="input-group-control" className="flex field-sizing-content min-h-16 w-full resize-none rounded-md bg-input-fill px-3 py-2 text-base transition-[color,box-shadow] outline-none motion-reduce:transition-none" placeholder="Autoresize textarea..." /> <InputGroupAddon align="block-end">how</InputGroupAddon> </InputGroup> );}API Reference
InputGroup
The main component that wraps inputs and addons.
| Prop | Type | Default |
|---|---|---|
className |
string |
<InputGroup> <InputGroupInput /> <InputGroupAddon /></InputGroup>InputGroupAddon
Displays icons, text, buttons, or other content alongside inputs.
| Prop | Type | Default |
|---|---|---|
separator |
boolean (block alignments only) |
false |
align |
"inline-start" | "inline-end" | "block-start" | "block-end" |
"inline-start" |
className |
string |
<InputGroupAddon align="inline-end"> <SearchIcon /></InputGroupAddon>For <InputGroupInput />, use the inline-start or inline-end alignment. For <InputGroupTextarea />, use the block-start or block-end alignment.
The InputGroupAddon component can have multiple InputGroupButton components and icons.
<InputGroupAddon> <InputGroupButton>Button</InputGroupButton> <InputGroupButton>Button</InputGroupButton></InputGroupAddon>InputGroupButton
Displays buttons within input groups.
| Prop | Type | Default |
|---|---|---|
shape |
"default" | "pill" |
"default" |
size |
"xs" | "icon-xs" | "sm" | "icon-sm" |
"xs" |
variant |
"default" | "destructive" | "outline" | "secondary" | "ghost" | "link" |
"ghost" |
className |
string |
<InputGroupButton>Button</InputGroupButton><InputGroupButton size="icon-xs" aria-label="Copy"> <CopyIcon /></InputGroupButton>InputGroupInput
Replacement for <Input /> when building input groups. This component has the input group styles pre-applied, and the surrounding <InputGroup /> handles its focus state automatically.
| Prop | Type | Default |
|---|---|---|
className |
string |
All other props are passed through to the underlying <Input /> component.
<InputGroup> <InputGroupInput placeholder="Enter text..." /> <InputGroupAddon> <SearchIcon /> </InputGroupAddon></InputGroup>InputGroupTextarea
Replacement for <Textarea /> when building input groups. This component has the textarea group styles pre-applied, and the surrounding <InputGroup /> handles its focus state automatically.
| Prop | Type | Default |
|---|---|---|
className |
string |
All other props are passed through to the underlying <Textarea /> component.
<InputGroup> <InputGroupTextarea placeholder="Enter message..." /> <InputGroupAddon align="block-end"> <InputGroupButton>Send</InputGroupButton> </InputGroupAddon></InputGroup>Props
Credits
- We take our inspiration from Shadcn UI for the
input-groupcomponent and style.