Components
- Accordion
- Alert
- Alert Dialog
- Aspect Ratio
- Attachment
- Avatar
- Badge
- Breadcrumb
- Bubble
- Button
- Button Group
- Calendar
- Card
- Carousel
- Chart
- Checkbox
- Collapsible
- Combobox
- Command
- Context Menu
- Date Picker
- Dialog
- Drawer
- Dropdown Menu
- Empty
- Field
- Hover Card
- Input
- Input OTP
- Input Group
- Item
- Kbd
- Label
- Marker
- Menubar
- Message
- Message Scroller
- Native Select
- Navigation Menu
- Pagination
- Popover
- Progress
- Radio Group
- Resizable
- Scroll Area
- Select
- Separator
- Sheet
- Sidebar
- Skeleton
- Slider
- Sonner
- Spinner
- Switch
- Table
- Tabs
- Textarea
- Toggle
- Toggle Group
- Tooltip
- New Component
Elements
Charts
Icons
https://
USD
import { Copy, DollarSign, Globe, Search } from "lucide-react";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { InputGroup, InputGroupText } from "@/components/ui/input-group";
export const InputGroupDemo = () => (
<div className="flex w-full max-w-sm flex-col gap-4">
{/* Icon prefix */}
<InputGroup>
<InputGroupText><Search /></InputGroupText>
<Input placeholder="Search..." />
</InputGroup>
{/* Text prefix */}
<InputGroup>
<InputGroupText><Globe /></InputGroupText>
<InputGroupText className="text-muted-foreground/60">https://</InputGroupText>
<Input placeholder="example.com" />
</InputGroup>
{/* Currency prefix + text suffix */}
<InputGroup>
<InputGroupText><DollarSign /></InputGroupText>
<Input type="number" placeholder="0.00" />
<InputGroupText>USD</InputGroupText>
</InputGroup>
{/* Input + button suffix */}
<InputGroup>
<Input defaultValue="https://ing.design/r/button" readOnly />
<Button variant="outline">
<Copy />
Copy
</Button>
</InputGroup>
</div>
);Icon prefix
Wrap a lucide icon in InputGroupText to add a decorative icon that labels the field.
import { Search } from "lucide-react";
import { Input } from "@/components/ui/input";
import { InputGroup, InputGroupText } from "@/components/ui/input-group";
<InputGroup>
<InputGroupText>
<Search />
</InputGroupText>
<Input placeholder="Search..." />
</InputGroup>Text prefix or suffix
Use InputGroupText for static text such as a URL scheme, currency code, or unit label.
<InputGroup>
<InputGroupText>https://</InputGroupText>
<Input placeholder="example.com" />
</InputGroup>
<InputGroup>
<Input type="number" placeholder="0.00" />
<InputGroupText>kg</InputGroupText>
</InputGroup>Both sides
Prefix and suffix can be combined freely.
import { DollarSign } from "lucide-react";
<InputGroup>
<InputGroupText>
<DollarSign />
</InputGroupText>
<Input type="number" placeholder="0.00" />
<InputGroupText>USD</InputGroupText>
</InputGroup>Button suffix
Place a Button as a direct child of InputGroup. The component uses data-slot selectors to strip the button's adjacent border-radius and collapse its left border against the input.
import { Copy } from "lucide-react";
import { Button } from "@/components/ui/button";
<InputGroup>
<Input defaultValue="https://ing.design/r/button" readOnly />
<Button variant="outline">
<Copy />
Copy
</Button>
</InputGroup>With Field
InputGroup composes cleanly with the Field component for accessible labels, descriptions, and error messages.
import { Field, FieldLabel, FieldDescription, FieldError, useField } from "@/components/ui/field";
import { Globe } from "lucide-react";
function FieldInput(props) {
const { id, error } = useField();
return (
<InputGroup>
<InputGroupText>
<Globe />
</InputGroupText>
<Input
id={id}
aria-invalid={!!error}
aria-describedby={error ? `${id}-error` : `${id}-description`}
{...props}
/>
</InputGroup>
);
}
<Field>
<FieldLabel>Website</FieldLabel>
<FieldInput placeholder="example.com" />
<FieldDescription>Your public website URL.</FieldDescription>
</Field>Props
InputGroup
All props are forwarded to the underlying<div>. The component adds no required props — place Input, InputGroupText, and Button as direct children.
InputGroupText
| Prop | Type | Default | Description |
|---|---|---|---|
className | string | — | Merged with addon styles. Use px-2.5 to tighten icon-only addons. |
Usage
import { Input } from "@/components/ui/input";
import { InputGroup, InputGroupText } from "@/components/ui/input-group";
<InputGroup>
<InputGroupText>$</InputGroupText>
<Input type="number" placeholder="0.00" />
</InputGroup>Specs
# Mint — Input Group Specs
## Component
- name: input-group
- file: registry/mint/input-group.tsx
- installs to: components/ui/input-group.tsx
- dependencies: none (uses only React and cn utility)
- registryDependencies: input, button
## What is it
A layout wrapper that merges an `Input` with one or more addons — static text,
icons, or action `Button`s — into a visually unified field with shared borders
and seamless rounded corners only on the outermost edges. Use it when a field
needs a contextual prefix or suffix (URL scheme, currency symbol, unit label,
copy button). Do not use it as a general flex container — children must carry
`data-slot` attributes for the selectors to work.
## Visual identity
Addons use the muted surface (`--muted`) with a matching `--input` border, so
they read as part of the field rather than separate elements. Radius is applied
only to the outermost corners (`rounded-l-md` / `rounded-r-md`), creating a
pill-like group with no internal gaps. Mint's default radius (1.25rem)
keeps the group soft and rounded.
## Design tokens
--input: oklch(0.88 0.04 155 / 60%) / oklch(0.32 0.05 155 / 40%) — addon and input border colour
--muted: oklch(0.96 0.02 155) / oklch(0.2 0.03 155) — addon background
--muted-foreground: oklch(0.52 0.06 155) / oklch(0.6 0.06 155) — addon text and icon colour
--ring: oklch(0.5 0.14 155) / oklch(0.62 0.15 155) — focus ring on Input / Button children
--radius: 1.25rem — outermost corner radius (via rounded-l-md / rounded-r-md)
## Sub-components
- InputGroup → flex container; adjusts radius and negative margin on direct Input and Button children via data-slot selectors
- InputGroupText → static addon (text, icon, or both); muted background, input border, first/last corner radius
## States
- focus-visible (Input child): relative + z-10 so the focus ring renders above adjacent addon borders
- focus-visible (Button child): relative + z-10, same stacking behaviour
- No disabled or error state is applied at the group level — handle these on the Input child directly
## Conventions
- Children must be direct (not nested) for the data-slot selectors to apply
- For icon-only addons use `className="px-2.5"` on `InputGroupText` to tighten horizontal padding
- SVG icons inside `InputGroupText` auto-size to 16px — do not set a size class unless overriding intentionally
- `InputGroup` does not wire up ARIA — wrap with `Field` + `useField()` to connect label, description, and error
- Sub-components expose `data-slot="input-group"`, `data-slot="input-group-text"` for CSS targeting
- Button children must use `variant="outline"` to match the input border weight visuallyInstallation
$ npx shadcn add \https://gin-design.vercel.app/input-group