JGuang / HeroUI

InputGroup

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

Import

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

Usage

HeroUI preview

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.

HeroUI preview

With Suffix Icon

Add an icon after the input field.

HeroUI preview

With Prefix and Suffix

Combine both prefix and suffix elements.

HeroUI preview

Text Prefix

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

HeroUI preview

Text Suffix

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

HeroUI preview

Icon Prefix and Text Suffix

Combine an icon prefix with a text suffix.

HeroUI preview

Copy Button Suffix

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

HeroUI preview

Icon Prefix and Copy Button

Combine an icon prefix with an interactive button suffix.

HeroUI preview

Password Toggle

Use a button in the suffix to toggle password visibility.

HeroUI preview

Loading State

Show a loading spinner in the suffix to indicate processing.

HeroUI preview

Keyboard Shortcut

Display keyboard shortcuts using the Kbd component.

HeroUI preview

Badge Suffix

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

HeroUI preview

Required Field

InputGroup respects the required state from its parent TextField.

HeroUI preview

Validation

InputGroup automatically reflects invalid state from its parent TextField.

HeroUI preview

Disabled State

InputGroup respects the disabled state from its parent TextField.

HeroUI preview

Full Width

HeroUI preview

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
HeroUI preview

In Surface

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

HeroUI preview

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.

HeroUI preview

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>
  );
}

Local source: vendor/en/react/components/(forms)/input-group.mdx

Generated from the pinned HeroUI v3 commit with internal links and previews adapted for JGuang.

On this page