> For AI agents: the complete documentation index is available at https://wallarm.github.io/design-system/llms.txt, the full documentation bundle is available at https://wallarm.github.io/design-system/llms-full.txt.

# InputGroup

Joins a field to whatever sits against it — an icon, a unit, a shortcut hint, a button — inside one bordered box that focuses as a single control. Reach for `Field` instead when what you need is a label and a description rather than something attached to the field itself.

[Source](https://github.com/wallarm/design-system/tree/main/packages/design-system/src/components/InputGroup) · [Storybook](https://wallarm.github.io/design-system/storybook/?path=/docs/inputs-inputgroup--overview)

```tsx
import { Info, Search } from '@wallarm-org/design-system/icons';
import { Input } from '@wallarm-org/design-system/Input';
import { InputGroup, InputGroupAddon, InputGroupText } from '@wallarm-org/design-system/InputGroup';
import { VStack } from '@wallarm-org/design-system/Stack';

export const Basic = () => (
  <VStack gap={12}>
    <InputGroup data-testid='input-group'>
      <InputGroupAddon>
        <Search />
      </InputGroupAddon>
      <Input placeholder='Enter' data-testid='input-group-input' />
      <InputGroupAddon align='inline-end'>
        <Info />
      </InputGroupAddon>
    </InputGroup>

    <InputGroup>
      <InputGroupAddon variant='outline'>
        <InputGroupText>https://</InputGroupText>
      </InputGroupAddon>
      <Input placeholder='Enter' value='wallarm/user-settings' />
      <InputGroupAddon variant='outline' align='inline-end'>
        <InputGroupText>.com</InputGroupText>
      </InputGroupAddon>
    </InputGroup>
  </VStack>
);
```

## Usage

```tsx
import { Info, Search } from '@wallarm-org/design-system/icons';
import { Input } from '@wallarm-org/design-system/Input';
import { InputGroup, InputGroupAddon, InputGroupText } from '@wallarm-org/design-system/InputGroup';
import { VStack } from '@wallarm-org/design-system/Stack';
```

## Examples

### Disabled

Disabling the control dims the whole group, addons included, so the box reads as one
unavailable thing rather than a live button next to a dead field.

```tsx
import { Info, Search } from '@wallarm-org/design-system/icons';
import { Input } from '@wallarm-org/design-system/Input';
import { InputGroup, InputGroupAddon, InputGroupText } from '@wallarm-org/design-system/InputGroup';
import { VStack } from '@wallarm-org/design-system/Stack';

export const Disabled = () => (
  <VStack gap={12}>
    <InputGroup>
      <InputGroupAddon>
        <Search />
      </InputGroupAddon>
      <Input placeholder='Enter' disabled />
      <InputGroupAddon align='inline-end'>
        <Info />
      </InputGroupAddon>
    </InputGroup>

    <InputGroup>
      <InputGroupAddon>
        <InputGroupText>https://</InputGroupText>
      </InputGroupAddon>
      <Input placeholder='Enter' value='wallarm/user-settings' disabled />
      <InputGroupAddon align='inline-end'>
        <InputGroupText>.com</InputGroupText>
      </InputGroupAddon>
    </InputGroup>
  </VStack>
);
```

### With error

The error border is drawn by the group for the same reason, keeping the red outline around
everything the reader thinks of as the field.

```tsx
import { Info, Search } from '@wallarm-org/design-system/icons';
import { Input } from '@wallarm-org/design-system/Input';
import { InputGroup, InputGroupAddon, InputGroupText } from '@wallarm-org/design-system/InputGroup';
import { VStack } from '@wallarm-org/design-system/Stack';

export const WithError = () => (
  <VStack gap={12}>
    <InputGroup>
      <InputGroupAddon>
        <Search />
      </InputGroupAddon>
      <Input placeholder='Enter' error />
      <InputGroupAddon align='inline-end'>
        <Info />
      </InputGroupAddon>
    </InputGroup>

    <InputGroup>
      <InputGroupAddon>
        <InputGroupText>https://</InputGroupText>
      </InputGroupAddon>
      <Input placeholder='Enter' value='wallarm/user-settings' error />
      <InputGroupAddon align='inline-end'>
        <InputGroupText>.com</InputGroupText>
      </InputGroupAddon>
    </InputGroup>
  </VStack>
);
```

### With loader

A `Loader` as a trailing addon, for a field that validates or searches as you type. It
replaces nothing, so the text doesn't shift when it appears.

```tsx
import { Input } from '@wallarm-org/design-system/Input';
import { InputGroup, InputGroupAddon } from '@wallarm-org/design-system/InputGroup';
import { Loader } from '@wallarm-org/design-system/Loader';

export const WithLoader = () => (
  <InputGroup>
    <Input placeholder='Searching...' disabled />
    <InputGroupAddon align='inline-end'>
      <Loader size='md' />
    </InputGroupAddon>
  </InputGroup>
);
```

### With kbd

A `Kbd` addon showing the shortcut that focuses the field — the search-box convention.
Only worth it where the shortcut actually exists.

```tsx
import { Search } from '@wallarm-org/design-system/icons';
import { Input } from '@wallarm-org/design-system/Input';
import { InputGroup, InputGroupAddon } from '@wallarm-org/design-system/InputGroup';
import { Kbd } from '@wallarm-org/design-system/Kbd';

export const WithKbd = () => (
  <InputGroup>
    <InputGroupAddon>
      <Search />
    </InputGroupAddon>
    <Input placeholder='Search' />
    <InputGroupAddon align='inline-end'>
      <Kbd>⌘</Kbd>
      <Kbd>K</Kbd>
    </InputGroupAddon>
  </InputGroup>
);
```

### With tooltip

An addon that explains the field, for when the reason is longer than a description line but
shorter than help text.

```tsx
import { Info, Search } from '@wallarm-org/design-system/icons';
import { Input } from '@wallarm-org/design-system/Input';
import { InputGroup, InputGroupAddon } from '@wallarm-org/design-system/InputGroup';
import { Tooltip, TooltipContent, TooltipTrigger } from '@wallarm-org/design-system/Tooltip';

export const WithTooltip = () => (
  <InputGroup>
    <InputGroupAddon>
      <Search />
    </InputGroupAddon>
    <Input placeholder='Enter' />
    <InputGroupAddon align='inline-end'>
      <Tooltip>
        <TooltipTrigger asChild>
          <Info />
        </TooltipTrigger>
        <TooltipContent>Get more info</TooltipContent>
      </Tooltip>
    </InputGroupAddon>
  </InputGroup>
);
```

### With textarea

The group also wraps a `Textarea`, with `align='block-end'` putting the addon under the
text rather than beside it — this is the composer shape.

```tsx
import { Button } from '@wallarm-org/design-system/Button';
import { ArrowUp, Settings2 } from '@wallarm-org/design-system/icons';
import { InputGroup, InputGroupAddon } from '@wallarm-org/design-system/InputGroup';
import { HStack, VStack } from '@wallarm-org/design-system/Stack';
import { Textarea } from '@wallarm-org/design-system/Textarea';

export const WithTextarea = () => (
  <div style={{ width: 480 }}>
    <VStack gap={12}>
      <InputGroup>
        <Textarea minRows={1} maxRows={5} placeholder='Type a message...' />
      </InputGroup>

      <InputGroup>
        <Textarea minRows={1} maxRows={5} placeholder='Type a message...' />
        <InputGroupAddon align='block-end'>
          <HStack fullWidth align='center' justify='end'>
            <Button variant='primary' color='brand' size='small'>
              <ArrowUp />
            </Button>
          </HStack>
        </InputGroupAddon>
      </InputGroup>

      <InputGroup>
        <Textarea minRows={1} maxRows={5} placeholder='Type a message...' />
        <InputGroupAddon align='block-end'>
          <HStack fullWidth align='center' justify='between'>
            <Button variant='secondary' size='small' color='neutral'>
              <Settings2 />
            </Button>
            <Button variant='primary' color='brand' size='small'>
              <ArrowUp />
            </Button>
          </HStack>
        </InputGroupAddon>
      </InputGroup>
    </VStack>
  </div>
);
```

### With select

A `Select` as an addon, for a unit or scope that changes what the value means. Keep it on
the side the reader reads last.

```tsx
import { createListCollection } from '@ark-ui/react/collection';
import { LayoutGrid, LayoutTemplate, Search } from '@wallarm-org/design-system/icons';
import { Input } from '@wallarm-org/design-system/Input';
import { InputGroup, InputGroupAddon } from '@wallarm-org/design-system/InputGroup';
import { Select, SelectButton, SelectContent, SelectOption, SelectOptionIndicator, SelectOptionText, SelectPositioner } from '@wallarm-org/design-system/Select';
import { VStack } from '@wallarm-org/design-system/Stack';

export const WithSelect = () => {
  const collection = createListCollection({
    items: [
      {
        label: 'React',
        value: 'react',
        icon: LayoutGrid,
        category: 'Frontend',
      },
      {
        label: 'Vue',
        value: 'vue',
        icon: LayoutTemplate,
        category: 'Frontend',
      },
      {
        label: 'Angular',
        value: 'angular',
        icon: Search,
        category: 'Frontend',
      },
    ],
  });

  return (
    <VStack gap={12}>
      <InputGroup>
        <InputGroupAddon variant='outline'>
          <Select collection={collection}>
            <SelectButton />

            <SelectPositioner>
              <SelectContent>
                {collection.items.map(skill => (
                  <SelectOption key={skill.value} item={skill}>
                    <SelectOptionText>{skill.label}</SelectOptionText>
                    <SelectOptionIndicator />
                  </SelectOption>
                ))}
              </SelectContent>
            </SelectPositioner>
          </Select>
        </InputGroupAddon>

        <Input placeholder='Enter' />
      </InputGroup>

      <InputGroup>
        <Input placeholder='Enter' />
        <InputGroupAddon align='inline-end' variant='outline'>
          <Select collection={collection}>
            <SelectButton />

            <SelectPositioner>
              <SelectContent>
                {collection.items.map(skill => (
                  <SelectOption key={skill.value} item={skill}>
                    <SelectOptionText>{skill.label}</SelectOptionText>
                    <SelectOptionIndicator />
                  </SelectOption>
                ))}
              </SelectContent>
            </SelectPositioner>
          </Select>
        </InputGroupAddon>
      </InputGroup>

      <InputGroup>
        <InputGroupAddon>
          <Select collection={collection}>
            <SelectButton />

            <SelectPositioner>
              <SelectContent>
                {collection.items.map(skill => (
                  <SelectOption key={skill.value} item={skill}>
                    <SelectOptionText>{skill.label}</SelectOptionText>
                    <SelectOptionIndicator />
                  </SelectOption>
                ))}
              </SelectContent>
            </SelectPositioner>
          </Select>
        </InputGroupAddon>

        <Input placeholder='Enter' />
      </InputGroup>

      <InputGroup>
        <Input placeholder='Enter' />
        <InputGroupAddon align='inline-end'>
          <Select collection={collection}>
            <SelectButton />

            <SelectPositioner>
              <SelectContent>
                {collection.items.map(skill => (
                  <SelectOption key={skill.value} item={skill}>
                    <SelectOptionText>{skill.label}</SelectOptionText>
                    <SelectOptionIndicator />
                  </SelectOption>
                ))}
              </SelectContent>
            </SelectPositioner>
          </Select>
        </InputGroupAddon>
      </InputGroup>
    </VStack>
  );
};
```

## Props

| Prop           | Type                                                                         | Default   | Description |
| -------------- | ---------------------------------------------------------------------------- | --------- | ----------- |
| defaultChecked | `boolean \| undefined`                                                       |           |             |
| defaultValue   | `string \| number \| readonly string[] \| undefined`                         |           |             |
| autoFocus      | `boolean \| undefined`                                                       |           |             |
| id             | `string \| undefined`                                                        |           |             |
| tabIndex       | `number \| undefined`                                                        |           |             |
| title          | `string \| undefined`                                                        |           |             |
| rel            | `string \| undefined`                                                        |           |             |
| onChange       | `ChangeEventHandler<T, Element> \| undefined`                                |           |             |
| size           | `{ default: string; medium: string; small: string; 'inline-edit': string; }` | `default` |             |
| data-testid    | `string \| undefined`                                                        |           |             |

## Explorer

