- Accordion
- Alert
- Alert Dialog
- Attachment
- Badge
- Breadcrumb
- Bubble
- Button
- Button Group
- Calendar
- Card
- Checkbox
- Collapsible
- Command
- Context Menu
- Data Table
- Dialog
- Drawer
- Dropdown Menu
- Empty
- Field
- Hover Card
- Input
- Input Group
- Item
- Kbd
- Label
- Marker
- Menubar
- Message
- Message Scroller
- Pagination
- Popover
- Progress
- Questionnaire
- Radio Group
- Scroll Area
- Select
- Separator
- Sheet
- Sidebar
- Skeleton
- Slider
- Sonner
- Spinner
- Switch
- Table
- Tabs
- Textarea
- Toggle
- Toggle Group
- Tooltip
import { MailIcon, SearchIcon } from "lucide-react"
import {
InputGroup,
InputGroupAddon,
InputGroupInput,
} from "@/components/ui/input-group"
export function InputGroupDemo() {
return (
<div className="flex flex-wrap items-center gap-2">
<InputGroup className="max-w-xs">
<InputGroupInput
placeholder="Quick actions"
aria-label="Quick actions"
/>
<InputGroupAddon>
<SearchIcon />
</InputGroupAddon>
</InputGroup>
<InputGroup className="max-w-xs">
<InputGroupInput
type="email"
placeholder="you@studio.com"
aria-label="Email"
/>
<InputGroupAddon>
<MailIcon />
</InputGroupAddon>
</InputGroup>
</div>
)
}Installation#
pnpm dlx shadcn@latest add https://ui.ikramhasan.com/r/input-group.json
Usage#
import {
InputGroup,
InputGroupAddon,
InputGroupButton,
InputGroupInput,
InputGroupText,
InputGroupTextarea,
} from "@/components/ui/input-group"<InputGroup>
<InputGroupInput placeholder="Search..." />
<InputGroupAddon>
<SearchIcon />
</InputGroupAddon>
</InputGroup>Examples#
Text#
import {
InputGroup,
InputGroupAddon,
InputGroupInput,
InputGroupText,
} from "@/components/ui/input-group"
export function InputGroupTextExample() {
return (
<InputGroup className="max-w-xs">
<InputGroupInput placeholder="acme" aria-label="Store" />
<InputGroupAddon>
<InputGroupText>https://</InputGroupText>
</InputGroupAddon>
<InputGroupAddon align="inline-end">
<InputGroupText>.myshopify.com</InputGroupText>
</InputGroupAddon>
</InputGroup>
)
}Button#
import { CopyIcon } from "lucide-react"
import {
InputGroup,
InputGroupAddon,
InputGroupButton,
InputGroupInput,
} from "@/components/ui/input-group"
export function InputGroupButtonExample() {
return (
<div className="flex flex-wrap items-center gap-2">
<InputGroup className="max-w-xs">
<InputGroupInput
defaultValue="sk_live_51H8…"
readOnly
aria-label="API key"
/>
<InputGroupAddon align="inline-end">
<InputGroupButton size="icon-xs" aria-label="Copy">
<CopyIcon />
</InputGroupButton>
</InputGroupAddon>
</InputGroup>
<InputGroup className="max-w-xs">
<InputGroupInput
placeholder="Invite by email"
aria-label="Invite by email"
/>
<InputGroupAddon align="inline-end">
<InputGroupButton size="sm" variant="secondary">
Invite
</InputGroupButton>
</InputGroupAddon>
</InputGroup>
</div>
)
}Textarea#
import { ArrowUpIcon, PlusIcon } from "lucide-react"
import {
InputGroup,
InputGroupAddon,
InputGroupButton,
InputGroupText,
InputGroupTextarea,
} from "@/components/ui/input-group"
export function InputGroupTextareaExample() {
return (
<InputGroup className="max-w-md">
<InputGroupTextarea placeholder="Ask anything…" aria-label="Message" />
<InputGroupAddon align="block-end">
<InputGroupButton
size="icon-xs"
variant="secondary"
aria-label="Attach"
>
<PlusIcon />
</InputGroupButton>
<InputGroupText className="ml-auto">0 / 2000</InputGroupText>
<InputGroupButton
size="icon-xs"
variant="default"
className="rounded-full"
aria-label="Send"
>
<ArrowUpIcon />
</InputGroupButton>
</InputGroupAddon>
</InputGroup>
)
}Invalid and disabled#
import { MailIcon, SearchIcon } from "lucide-react"
import {
InputGroup,
InputGroupAddon,
InputGroupInput,
} from "@/components/ui/input-group"
export function InputGroupInvalid() {
return (
<div className="flex flex-wrap items-center gap-2">
<InputGroup className="max-w-xs">
<InputGroupInput
defaultValue="not-an-email"
aria-invalid
aria-label="Email"
/>
<InputGroupAddon>
<MailIcon />
</InputGroupAddon>
</InputGroup>
<InputGroup className="max-w-xs" data-disabled>
<InputGroupInput
disabled
placeholder="Disabled"
aria-label="Disabled"
/>
<InputGroupAddon>
<SearchIcon />
</InputGroupAddon>
</InputGroup>
</div>
)
}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.
For proper focus navigation, the InputGroupAddon component should be placed
after the input. Set the align prop to position the addon.
| Prop | Type | Default |
|---|---|---|
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 |
|---|---|---|
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 uses the unified data-slot="input-group-control" for focus state handling.
| 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 uses the unified data-slot="input-group-control" for focus state handling.
| 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>