Components
Attach addons, buttons, and helper text to inputs and textareas.
Playground
align, so focus lands on the field first.import {
InputGroup,
InputGroupAddon,
InputGroupInput,
InputGroupText,
} from "@workspace/ui/components/input-group"
<InputGroup>
<InputGroupInput placeholder="Search..." />
<InputGroupAddon>
<MagnifyingGlassIcon />
</InputGroupAddon>
<InputGroupAddon align="inline-end">
<InputGroupText>12 results</InputGroupText>
</InputGroupAddon>
</InputGroup>align values: inline-start and inline-end sit inside the row, while block-start and block-end switch the group to a column and span the full width — the group grows to h-auto automatically.<InputGroup>
<InputGroupInput placeholder="Search..." />
<InputGroupAddon align="inline-start">
<MagnifyingGlassIcon />
</InputGroupAddon>
</InputGroup>
<InputGroup>
<InputGroupInput placeholder="Searching..." />
<InputGroupAddon align="inline-end">
<Spinner />
</InputGroupAddon>
</InputGroup>
<InputGroup>
<InputGroupInput id="name" placeholder="Enter your name" />
<InputGroupAddon align="block-start">
<InputGroupText>Full Name</InputGroupText>
</InputGroupAddon>
</InputGroup>
<InputGroup>
<InputGroupInput placeholder="Enter amount" />
<InputGroupAddon align="block-end">
<InputGroupText>USD</InputGroupText>
</InputGroupAddon>
</InputGroup>size-4 and inherit text-muted-foreground. A group accepts addons on both edges, and one addon can hold several icons.<InputGroup>
<InputGroupInput type="email" placeholder="Enter your email" />
<InputGroupAddon>
<EnvelopeIcon />
</InputGroupAddon>
</InputGroup>
<InputGroup>
<InputGroupInput placeholder="Card number" />
<InputGroupAddon>
<CreditCardIcon />
</InputGroupAddon>
<InputGroupAddon align="inline-end">
<CheckIcon />
</InputGroupAddon>
</InputGroup><InputGroup>
<InputGroupAddon>
<InputGroupText>$</InputGroupText>
</InputGroupAddon>
<InputGroupInput placeholder="0.00" />
<InputGroupAddon align="inline-end">
<InputGroupText>USD</InputGroupText>
</InputGroupAddon>
</InputGroup>
<InputGroup>
<InputGroupAddon>
<InputGroupText>https://</InputGroupText>
</InputGroupAddon>
<InputGroupInput placeholder="example.com" />
</InputGroup>
<InputGroup>
<InputGroupInput placeholder="Enter your username" />
<InputGroupAddon align="inline-end">
<InputGroupText>@company.com</InputGroupText>
</InputGroupAddon>
</InputGroup>xs (default), icon-xs, sm, and icon-sm. The variant defaults to ghost; icon-only buttons need an aria-label.<InputGroup>
<InputGroupInput placeholder="https://x.com/westy" readOnly />
<InputGroupAddon align="inline-end">
<InputGroupButton size="icon-xs" aria-label="Copy">
<CopyIcon />
</InputGroupButton>
</InputGroupAddon>
</InputGroup>
<InputGroup>
<InputGroupInput placeholder="Type to search..." />
<InputGroupAddon align="inline-end">
<InputGroupButton variant="secondary">Search</InputGroupButton>
</InputGroupAddon>
</InputGroup><InputGroup>
<InputGroupInput placeholder="Search..." />
<InputGroupAddon>
<MagnifyingGlassIcon />
</InputGroupAddon>
<InputGroupAddon align="inline-end">
<Kbd>⌘K</Kbd>
</InputGroupAddon>
</InputGroup><InputGroup>
<InputGroupInput placeholder="Saving changes..." />
<InputGroupAddon align="inline-end">
<InputGroupText>Saving...</InputGroupText>
<Spinner />
</InputGroupAddon>
</InputGroup>block-start header and a block-end footer. Add border-b / border-t to the addons to separate them from the text area, and ml-auto to push actions to the end.<InputGroup>
<InputGroupTextarea
placeholder="console.log('Hello, world!');"
className="min-h-[140px] font-mono text-sm"
/>
<InputGroupAddon align="block-start" className="border-b">
<InputGroupText className="font-mono font-medium">
<FileJsIcon />
script.js
</InputGroupText>
<InputGroupButton size="icon-xs" className="ml-auto" aria-label="Copy">
<CopyIcon />
</InputGroupButton>
</InputGroupAddon>
<InputGroupAddon align="block-end" className="border-t">
<InputGroupText>Line 1, Column 1</InputGroupText>
<InputGroupButton size="sm" variant="default" className="ml-auto">
Run <ArrowElbowDownLeftIcon />
</InputGroupButton>
</InputGroupAddon>
</InputGroup>asChild — contextual actions without leaving the field.<InputGroup>
<InputGroupInput placeholder="Enter file name" />
<InputGroupAddon align="inline-end">
<DropdownMenu>
<DropdownMenuTrigger asChild>
<InputGroupButton size="icon-xs" aria-label="More">
<DotsThreeIcon />
</InputGroupButton>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DropdownMenuGroup>
<DropdownMenuItem>Settings</DropdownMenuItem>
<DropdownMenuItem>Copy path</DropdownMenuItem>
<DropdownMenuItem>Open location</DropdownMenuItem>
</DropdownMenuGroup>
</DropdownMenuContent>
</DropdownMenu>
</InputGroupAddon>
</InputGroup>dir="rtl" mirrors start and end addons without extra classes.<InputGroup dir="rtl">
<InputGroupInput placeholder="بحث..." />
<InputGroupAddon>
<MagnifyingGlassIcon />
</InputGroupAddon>
<InputGroupAddon align="inline-end">
<InputGroupText>١٢ نتيجة</InputGroupText>
</InputGroupAddon>
</InputGroup>role="group", and clicking an addon forwards focus into the input. Keep addons after the control in the DOM — align handles the visual order — so the tab sequence reaches the field before any buttons. Icon-only InputGroupButtons need an aria-label, and validation states are announced by setting aria-invalid on the control — the group border and ring restyle automatically.<InputGroup>
<InputGroupInput aria-invalid={hasError} placeholder="Email" />
<InputGroupAddon align="inline-end">
<InputGroupButton size="icon-xs" aria-label="Clear field">
<XIcon />
</InputGroupButton>
</InputGroupAddon>
</InputGroup>data-slot="input-group-control".| Component | Prop | Default |
|---|---|---|
| InputGroupAddon | align?: "inline-start" | "inline-end" | "block-start" | "block-end" | "inline-start" |
| InputGroupButton | size?: "xs" | "icon-xs" | "sm" | "icon-sm" | "xs" |
| InputGroupButton | variant?: React.ComponentProps<typeof Button>["variant"] | "ghost" |
| InputGroupInput | ...props: React.ComponentProps<"input"> | — |
| InputGroupTextarea | ...props: React.ComponentProps<"textarea"> | — |
<InputGroup data-slot="input-group" role="group" /> <InputGroupInput data-slot="input-group-control" /> <InputGroupTextarea data-slot="input-group-control" /> <InputGroupAddon data-slot="input-group-addon" data-align="inline-start|inline-end|block-start|block-end" /> <InputGroupButton data-size="xs|icon-xs|sm|icon-sm" /> <InputGroupText />
Tokens used
9 design tokens consumed by the Input Group component.
--input
Input
--ring
Ring
--destructive
Destructive
--muted-foreground
Muted Foreground
--text-sm
Text Small (14px)
--font-weight-medium
Font weight Medium (500)
--radius-md
Radius 0.8× (8px)
--radius
Radius base (10px)
--spacing
Spacing unit (4px)