ProComponents, templates & AI tooling
HeroUI
27.7k

InputGroup

Group related input controls with prefix and suffix elements for enhanced form fields

Import

import { InputGroup } from '@heroui/react';

Usage

Anatomy

import {InputGroup, TextField, Label} from '@heroui/react';

export default () => (
  <TextField>
    <Label />
    <InputGroup>
      <InputGroup.Prefix />
      <InputGroup.Input /> {/* Or use InputGroup.TextArea for multiline input */}
      <InputGroup.Suffix />
    </InputGroup>
  </TextField>
)

InputGroup wraps an input field with optional prefix and suffix elements, creating a visually cohesive group. It's typically used within TextField 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.

With Suffix Icon

Add an icon after the input field.

With Prefix and Suffix

Combine both prefix and suffix elements.

Text Prefix

Use text as a prefix, such as currency symbols or protocol prefixes.

Text Suffix

Use text as a suffix, such as domain extensions or units.

Icon Prefix and Text Suffix

Combine an icon prefix with a text suffix.

Copy Button Suffix

Add an interactive button in the suffix, such as a copy button.

Icon Prefix and Copy Button

Combine an icon prefix with an interactive button suffix.

Password Toggle

Use a button in the suffix to toggle password visibility.

Loading State

Show a loading spinner in the suffix to indicate processing.

Keyboard Shortcut

Display keyboard shortcuts using the Kbd component.

Badge Suffix

Add a badge or chip in the suffix to show status or labels.

Required Field

InputGroup respects the required state from its parent TextField.

Validation

InputGroup automatically reflects invalid state from its parent TextField.

Disabled State

InputGroup respects the disabled state from its parent TextField.

Full Width

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

In Surface

When used inside a Surface component, use variant="secondary" to apply the lower emphasis variant suitable for surface backgrounds.

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.

Styling

Passing Tailwind CSS classes

import {InputGroup, TextField, Label} from '@heroui/react';

function CustomInputGroup() {
  return (
    <TextField>
      <Label>Website</Label>
      <InputGroup className="rounded-xl border-2 border-primary">
        <InputGroup.Prefix className="bg-primary/10 text-primary">
          https://
        </InputGroup.Prefix>
        <InputGroup.Input className="font-medium" />
        <InputGroup.Suffix className="bg-primary/10 text-primary">
          .com
        </InputGroup.Suffix>
      </InputGroup>
    </TextField>
  );
}

Customizing the component classes

InputGroup uses CSS classes that can be customized. Override the component classes to match your design system.

@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 component.

Base Props

PropTypeDefaultDescription
childrenReact.ReactNode | (values: GroupRenderProps) => React.ReactNode-Child components (Input, TextArea, Prefix, Suffix) or render function.
classNamestring | (values: GroupRenderProps) => string-CSS classes for styling, supports render props.
styleReact.CSSProperties | (values: GroupRenderProps) => React.CSSProperties-Inline styles, supports render props.
fullWidthbooleanfalseWhether the input group should take full width of its container
idstring-The element's unique identifier.

Variant Props

PropTypeDefaultDescription
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

PropTypeDefaultDescription
aria-labelstring-Accessibility label when no visible label is present.
aria-labelledbystring-ID of elements that label this group.
aria-describedbystring-ID of elements that describe this group.
aria-detailsstring-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 component.

PropTypeDefaultDescription
classNamestring-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.
typestring'text'Input type (text, password, email, etc.).
valuestring-Current value (controlled).
defaultValuestring-Default value (uncontrolled).
placeholderstring-Placeholder text.
disabledboolean-Whether the input is disabled.
readOnlyboolean-Whether the input is read-only.

InputGroup.TextArea Props

InputGroup.TextArea inherits all props from React Aria's TextArea component.

PropTypeDefaultDescription
classNamestring-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.
valuestring-Current value (controlled).
defaultValuestring-Default value (uncontrolled).
placeholderstring-Placeholder text.
rowsnumber-Number of visible text lines.
disabledboolean-Whether the textarea is disabled.
readOnlyboolean-Whether the textarea is read-only.

InputGroup.Prefix Props

PropTypeDefaultDescription
childrenReact.ReactNode-Content to display in the prefix (icons, text, etc.).
classNamestring-CSS classes for styling.

InputGroup.Suffix Props

PropTypeDefaultDescription
childrenReact.ReactNode-Content to display in the suffix (icons, buttons, badges, etc.).
classNamestring-CSS classes for styling.

Usage Example

import {InputGroup, TextField, Label, Button} from '@heroui/react';
import {Icon} from '@iconify/react';

function Example() {
  return (
    <TextField>
      <Label>Email</Label>
      <InputGroup>
        <InputGroup.Prefix>
          <Icon icon="gravity-ui:envelope" />
        </InputGroup.Prefix>
        <InputGroup.Input placeholder="name@email.com" />
        <InputGroup.Suffix>
          <Button isIconOnly size="sm" variant="ghost">
            <Icon icon="gravity-ui:check" />
          </Button>
        </InputGroup.Suffix>
      </InputGroup>
    </TextField>
  );
}

TextArea Usage Example

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 (
    <TextField fullWidth isInvalid={feedback.length > 500} name="feedback" onChange={setFeedback}>
      <Label>Your Feedback</Label>
      <InputGroup fullWidth>
        <InputGroup.Prefix>
          <Envelope className="size-4 text-muted" />
        </InputGroup.Prefix>
        <InputGroup.TextArea
          className="resize-none"
          placeholder="Share your thoughts, suggestions, or issues..."
          rows={5}
          value={feedback}
        />
      </InputGroup>
      <Description className="flex w-full items-center justify-between px-1">
        <span>Maximum 500 characters.</span>
        <span className="ml-auto">{feedback.length}/500</span>
      </Description>
      <FieldError>Feedback must be less than 500 characters</FieldError>
    </TextField>
  );
}

On this page