# InputGroup **Category**: react **URL**: https://www.heroui.com/docs/react/components/input-group **Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/react/components/(forms)/input-group.mdx > Group related input controls with prefix and suffix elements for enhanced form fields *** ## Import ```tsx import { InputGroup } from '@heroui/react'; ``` ### Usage ```tsx "use client"; import {Envelope} from "@gravity-ui/icons"; import {InputGroup, Label, TextField} from "@heroui/react"; export function Default() { return ( ); } ``` ### Anatomy ```tsx import {InputGroup, TextField, Label} from '@heroui/react'; export default () => ( ) ``` > **InputGroup** wraps an input field with optional prefix and suffix elements, creating a visually cohesive group. It's typically used within **[TextField](/docs/components/text-field)** to add icons, text, buttons, or other elements before or after the input. Use **InputGroup.Input** for single-line inputs or **InputGroup.TextArea** for multiline text inputs. ### With Prefix Icon Add an icon before the input field. ```tsx "use client"; import {Envelope} from "@gravity-ui/icons"; import {Description, InputGroup, Label, TextField} from "@heroui/react"; export function WithPrefixIcon() { return ( We'll never share this with anyone else ); } ``` ### With Suffix Icon Add an icon after the input field. ```tsx "use client"; import {Envelope} from "@gravity-ui/icons"; import {Description, InputGroup, Label, TextField} from "@heroui/react"; export function WithSuffixIcon() { return ( We don't send spam ); } ``` ### With Prefix and Suffix Combine both prefix and suffix elements. ```tsx "use client"; import {Description, InputGroup, Label, TextField} from "@heroui/react"; export function WithPrefixAndSuffix() { return ( $ USD What customers would pay ); } ``` ### Text Prefix Use text as a prefix, such as currency symbols or protocol prefixes. ```tsx "use client"; import {InputGroup, Label, TextField} from "@heroui/react"; export function WithTextPrefix() { return ( https:// ); } ``` ### Text Suffix Use text as a suffix, such as domain extensions or units. ```tsx "use client"; import {InputGroup, Label, TextField} from "@heroui/react"; export function WithTextSuffix() { return ( .com ); } ``` ### Icon Prefix and Text Suffix Combine an icon prefix with a text suffix. ```tsx "use client"; import {Globe} from "@gravity-ui/icons"; import {InputGroup, Label, TextField} from "@heroui/react"; export function WithIconPrefixAndTextSuffix() { return ( .com ); } ``` ### Copy Button Suffix Add an interactive button in the suffix, such as a copy button. ```tsx "use client"; import {Copy} from "@gravity-ui/icons"; import {Button, InputGroup, Label, TextField} from "@heroui/react"; export function WithCopySuffix() { return ( ); } ``` ### Icon Prefix and Copy Button Combine an icon prefix with an interactive button suffix. ```tsx "use client"; import {Copy, Globe} from "@gravity-ui/icons"; import {Button, InputGroup, Label, TextField} from "@heroui/react"; export function WithIconPrefixAndCopySuffix() { return ( ); } ``` ### Password Toggle Use a button in the suffix to toggle password visibility. ```tsx "use client"; import {Eye, EyeSlash} from "@gravity-ui/icons"; import {Button, InputGroup, Label, TextField} from "@heroui/react"; import {useState} from "react"; export function PasswordWithToggle() { const [isVisible, setIsVisible] = useState(false); return ( ); } ``` ### Loading State Show a loading spinner in the suffix to indicate processing. ```tsx "use client"; import {InputGroup, Spinner, TextField} from "@heroui/react"; export function WithLoadingSuffix() { return ( ); } ``` ### Keyboard Shortcut Display keyboard shortcuts using the [Kbd](/docs/components/kbd) component. ```tsx "use client"; import {InputGroup, Kbd, TextField} from "@heroui/react"; export function WithKeyboardShortcut() { return ( K ); } ``` ### Badge Suffix Add a badge or chip in the suffix to show status or labels. ```tsx "use client"; import {Chip, InputGroup, TextField} from "@heroui/react"; export function WithBadgeSuffix() { return ( Pro ); } ``` ### Required Field InputGroup respects the required state from its parent TextField. ```tsx "use client"; import {Envelope} from "@gravity-ui/icons"; import {Description, InputGroup, Label, TextField} from "@heroui/react"; export function Required() { return (
$ USD What customers would pay
); } ``` ### Validation InputGroup automatically reflects invalid state from its parent TextField. ```tsx "use client"; import {Envelope} from "@gravity-ui/icons"; import {FieldError, InputGroup, Label, TextField} from "@heroui/react"; export function Invalid() { return (
Please enter a valid email address $ USD Price must be greater than 0
); } ``` ### Disabled State InputGroup respects the disabled state from its parent TextField. ```tsx "use client"; import {Envelope} from "@gravity-ui/icons"; import {InputGroup, Label, TextField} from "@heroui/react"; export function Disabled() { return (
$ USD
); } ``` ### Full Width ```tsx import {Envelope, Eye} from "@gravity-ui/icons"; import {InputGroup, Label, TextField} from "@heroui/react"; export function FullWidth() { return (
); } ``` ### Variants The InputGroup component supports two visual variants: - **`primary`** (default) - Standard styling with shadow, suitable for most use cases - **`secondary`** - Lower emphasis variant without shadow, suitable for use in Surface components ```tsx import {Envelope} from "@gravity-ui/icons"; import {InputGroup, Label, TextField} from "@heroui/react"; export function Variants() { return (
); } ``` ### In Surface When used inside a [Surface](/docs/components/surface) component, use `variant="secondary"` to apply the lower emphasis variant suitable for surface backgrounds. ```tsx "use client"; import {Envelope} from "@gravity-ui/icons"; import {Description, InputGroup, Label, Surface, TextField} from "@heroui/react"; export function OnSurface() { return ( We'll never share this with anyone else ); } ``` ### With TextArea Use **InputGroup.TextArea** for multiline text inputs with prefix and suffix elements. When a textarea is present, the container automatically adjusts its height to accommodate the content and aligns prefix/suffix elements to the top. ```tsx "use client"; import {ArrowUp, At, Microphone, PlugConnection, Plus} from "@gravity-ui/icons"; import {Button, InputGroup, Kbd, Spinner, TextField, Tooltip} from "@heroui/react"; import {useState} from "react"; export function WithTextArea() { const [value, setValue] = useState(""); const [isSubmitting, setIsSubmitting] = useState(false); const handleSubmit = () => { if (!value.trim()) return; setIsSubmitting(true); setTimeout(() => { setIsSubmitting(false); setValue(""); }, 1000); }; return ( setValue(event.target.value)} />

Add a files and more

Connect apps

Voice input

Send

); } ``` ## Related Components - **TextField**: Composition-friendly fields with labels and validation - **Input**: Single-line text input built on React Aria - **Label**: Accessible label for form controls ## Styling ### Passing Tailwind CSS classes ```tsx import {InputGroup, TextField, Label} from '@heroui/react'; function CustomInputGroup() { return ( https:// .com ); } ``` ### Customizing the component classes InputGroup uses CSS classes that can be customized. Override the component classes to match your design system. ```css @layer components { .input-group { @apply bg-field text-field-foreground shadow-field rounded-field inline-flex min-h-9 items-center overflow-hidden border text-sm outline-none; } .input-group__input { @apply flex-1 rounded-none border-0 bg-transparent px-3 py-2 shadow-none outline-none; } .input-group__prefix { @apply text-field-placeholder rounded-l-field flex h-full items-center justify-center rounded-r-none bg-transparent px-3; } .input-group__suffix { @apply text-field-placeholder rounded-r-field flex h-full items-center justify-center rounded-l-none bg-transparent px-3; } /* Secondary variant */ .input-group--secondary { @apply shadow-none; background-color: var(--color-default); } } ``` ### CSS Classes - `.input-group` – Root container with border, background, and flex layout. Uses `min-h-9` for flexible height and `items-center` by default, switching to `items-start` when a textarea is present. - `.input-group__input` – Input element with transparent background and no border. Also used as the base class for textarea elements. - `.input-group__prefix` – Prefix container with left border radius. Aligns to top when used with textarea. - `.input-group__suffix` – Suffix container with right border radius. Aligns to top when used with textarea. - `.input-group--primary` – Primary variant with shadow (default) - `.input-group--secondary` – Secondary variant without shadow, suitable for use in surfaces **Note**: When using `InputGroup.TextArea`, the container automatically switches from `items-center` to `items-start` alignment and uses `height: auto` instead of a fixed height. Prefix and suffix elements align to the top with additional padding to match the textarea's vertical padding. The textarea uses the same `.input-group__input` base class with textarea-specific styles (minimum height and vertical resize) applied via the `[data-slot="input-group-textarea"]` attribute selector. ### Interactive States InputGroup automatically manages these data attributes based on its state: - **Hover**: `[data-hovered]` - Applied when hovering over the group - **Focus Within**: `[data-focus-within]` - Applied when the input is focused - **Invalid**: `[data-invalid]` - Applied when parent TextField is invalid - **Disabled**: `[data-disabled]` or `[aria-disabled]` - Applied when parent TextField is disabled ## API Reference ### InputGroup Props InputGroup inherits all props from React Aria's [Group](https://react-spectrum.adobe.com/react-aria/Group.html) component. #### Base Props | Prop | Type | Default | Description | |------|------|---------|-------------| | `children` | `React.ReactNode \| (values: GroupRenderProps) => React.ReactNode` | - | Child components (Input, TextArea, Prefix, Suffix) or render function. | | `className` | `string \| (values: GroupRenderProps) => string` | - | CSS classes for styling, supports render props. | | `style` | `React.CSSProperties \| (values: GroupRenderProps) => React.CSSProperties` | - | Inline styles, supports render props. | | `fullWidth` | `boolean` | `false` | Whether the input group should take full width of its container | | `id` | `string` | - | The element's unique identifier. | #### Variant Props | Prop | Type | Default | Description | |------|------|---------|-------------| | `variant` | `"primary" \| "secondary"` | `"primary"` | Visual variant of the component. `primary` is the default style with shadow. `secondary` is a lower emphasis variant without shadow, suitable for use in surfaces. | #### Accessibility Props | Prop | Type | Default | Description | |------|------|---------|-------------| | `aria-label` | `string` | - | Accessibility label when no visible label is present. | | `aria-labelledby` | `string` | - | ID of elements that label this group. | | `aria-describedby` | `string` | - | ID of elements that describe this group. | | `aria-details` | `string` | - | ID of elements with additional details. | | `role` | `'group' \| 'region' \| 'presentation'` | `'group'` | Accessibility role for the group. Use 'region' for important content, 'presentation' for visual-only grouping. | ### Composition Components InputGroup works with these subcomponents: - **InputGroup.Root** - Root container (also available as `InputGroup`) - **InputGroup.Input** - Single-line input element component - **InputGroup.TextArea** - Multiline textarea element component - **InputGroup.Prefix** - Prefix container component - **InputGroup.Suffix** - Suffix container component #### InputGroup.Input Props InputGroup.Input inherits all props from React Aria's [Input](https://react-spectrum.adobe.com/react-aria/Input.html) component. | Prop | Type | Default | Description | |------|------|---------|-------------| | `className` | `string` | - | CSS classes for styling. | | `variant` | `"primary" \| "secondary"` | `"primary"` | Visual variant of the input. `primary` is the default style with shadow. `secondary` is a lower emphasis variant without shadow, suitable for use in surfaces. | | `type` | `string` | `'text'` | Input type (text, password, email, etc.). | | `value` | `string` | - | Current value (controlled). | | `defaultValue` | `string` | - | Default value (uncontrolled). | | `placeholder` | `string` | - | Placeholder text. | | `disabled` | `boolean` | - | Whether the input is disabled. | | `readOnly` | `boolean` | - | Whether the input is read-only. | #### InputGroup.TextArea Props InputGroup.TextArea inherits all props from React Aria's [TextArea](https://react-spectrum.adobe.com/react-aria/TextArea.html) component. | Prop | Type | Default | Description | |------|------|---------|-------------| | `className` | `string` | - | CSS classes for styling. | | `variant` | `"primary" \| "secondary"` | `"primary"` | Visual variant of the textarea. `primary` is the default style with shadow. `secondary` is a lower emphasis variant without shadow, suitable for use in surfaces. | | `value` | `string` | - | Current value (controlled). | | `defaultValue` | `string` | - | Default value (uncontrolled). | | `placeholder` | `string` | - | Placeholder text. | | `rows` | `number` | - | Number of visible text lines. | | `disabled` | `boolean` | - | Whether the textarea is disabled. | | `readOnly` | `boolean` | - | Whether the textarea is read-only. | #### InputGroup.Prefix Props | Prop | Type | Default | Description | |------|------|---------|-------------| | `children` | `React.ReactNode` | - | Content to display in the prefix (icons, text, etc.). | | `className` | `string` | - | CSS classes for styling. | #### InputGroup.Suffix Props | Prop | Type | Default | Description | |------|------|---------|-------------| | `children` | `React.ReactNode` | - | Content to display in the suffix (icons, buttons, badges, etc.). | | `className` | `string` | - | CSS classes for styling. | ### Usage Example ```tsx import {InputGroup, TextField, Label, Button} from '@heroui/react'; import {Icon} from '@iconify/react'; function Example() { return ( ); } ``` ### TextArea Usage Example ```tsx import {Envelope} from "@gravity-ui/icons"; import {Description, FieldError, InputGroup, Label, TextField} from "@heroui/react"; import {useState} from "react"; function TextAreaExample() { const [feedback, setFeedback] = useState(""); return ( 500} name="feedback" onChange={setFeedback}> Maximum 500 characters. {feedback.length}/500 Feedback must be less than 500 characters ); } ```