# Input Group

## Usage

`InputGroup` joins a field with a prefix, a suffix, or a button so they read as one control. Use it for a unit, a protocol, or a short action.

Put fixed text in the `before` and `after` slots:

```vue
<script setup lang="ts">
import { InputGroup, InputGroupText } from '@astryx-vue/core/InputGroup'
import { TextInput } from '@astryx-vue/core/TextInput'
import { ref } from 'vue'

const domain = ref('')
</script>

<template>
  <InputGroup label="Website">
    <template #before>
      <InputGroupText>https://</InputGroupText>
    </template>
    <TextInput v-model="domain" label="URL" is-label-hidden placeholder="example" />
    <template #after>
      <InputGroupText>.com</InputGroupText>
    </template>
  </InputGroup>
</template>
```

Once the group has a label, it is a field. The label, description, optional or required mark, and status come from the shared field shell, so do not wrap another field around it. A control inside the group keeps its own label for that cell, usually hidden. Fixed text in the addons uses the group text component, which shares the addon type size and color. Without a label, the group stays a joined control that can sit inside a field that already exists.

### Anatomy

- **Label**: Text above the group.
- **Prefix addon**: Content before the input (text, icon, or button).
- **Input**: The main input element (TextInput, NumberInput, TimeInput, DateInput, Typeahead, Selector, or MultiSelector).
- **Suffix addon**: Content after the input (text, icon, or button).
- **Status message**: An error, warning, or success message below the group.

## Best practices

| Guideline | Practice |
| --- | --- |
| Do | Use `before` for a fixed prefix such as a unit or `https://`. |
| Do | Use `after` for a short action, such as clear or submit. |
| Do | Keep the addons short so the field itself stays easy to read. |
| Don't | Stack several addons on both sides. The field becomes cramped. |

## Examples

### Basic

A currency field with a static prefix and suffix around the amount.

```vue
<script setup lang="ts">
import { InputGroup, InputGroupText } from '@astryx-vue/core/InputGroup'
import { TextInput } from '@astryx-vue/core/TextInput'
import { ref } from 'vue'

const price = ref('')
</script>

<template>
  <div style="width: 320px; max-width: 100%">
    <InputGroup label="Price">
      <template #before>
        <InputGroupText>$</InputGroupText>
      </template>
      <TextInput v-model="price" label="Amount" is-label-hidden placeholder="0.00" />
      <template #after>
        <InputGroupText>USD</InputGroupText>
      </template>
    </InputGroup>
  </div>
</template>
```

### Website

The protocol and the domain suffix stay fixed on either side of the address.

```vue
<script setup lang="ts">
import { InputGroup, InputGroupText } from '@astryx-vue/core/InputGroup'
import { TextInput } from '@astryx-vue/core/TextInput'
import { ref } from 'vue'

const domain = ref('')
</script>

<template>
  <div style="width: 320px; max-width: 100%">
    <InputGroup label="Website">
      <template #before>
        <InputGroupText>https://</InputGroupText>
      </template>
      <TextInput v-model="domain" label="URL" is-label-hidden placeholder="example" />
      <template #after>
        <InputGroupText>.com</InputGroupText>
      </template>
    </InputGroup>
  </div>
</template>
```

### Field status

With a label, the description, optional mark, and error belong to the group.

```vue
<script setup lang="ts">
import { InputGroup, InputGroupText } from '@astryx-vue/core/InputGroup'
import { TextInput } from '@astryx-vue/core/TextInput'
import { ref } from 'vue'

const price = ref('')
</script>

<template>
  <div style="width: 320px; max-width: 100%">
    <InputGroup
      label="Price"
      description="Before tax"
      is-optional
      :status="{ type: 'error', message: 'Enter an amount' }"
    >
      <template #before>
        <InputGroupText>$</InputGroupText>
      </template>
      <TextInput v-model="price" label="Amount" is-label-hidden placeholder="0.00" />
      <template #after>
        <InputGroupText>USD</InputGroupText>
      </template>
    </InputGroup>
  </div>
</template>
```

## InputGroup Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `size` | `'sm' \| 'md' \| 'lg'` | `'md'` | Size of the group, passed through to the controls inside it. |
| `label` | `string` | — | Accessible name. When set, the group shows a label, description, optional or required mark, and status. |
| `isLabelHidden` | `boolean` | `false` | Hides the label visually. Screen readers still read it. |
| `description` | `string` | — | Help text between the label and the control. |
| `disabled` | `boolean` | `false` | Disables the group and the selectors inside it. |
| `isOptional` | `boolean` | `false` | Marks the label as optional. |
| `isRequired` | `boolean` | `false` | Marks the label as required. |
| `status` | `FieldStatusInput` | — | Status on the group border and under the control. |
| `labelTooltip` | `string` | — | Tooltip at the end of the label. |

## InputGroup slots

| Name | Description |
| --- | --- |
| `default` | The input control in the middle. |
| `before` | Text, icon, or button shown before the input. |
| `after` | Text, icon, or button shown after the input. |

## InputGroupText

Fixed text inside an addon. It has no props of its own. Put the text in the default slot.
