Skip to content

InputGroup ​

InputGroup replaces Input inside a field when the input needs a companion — an icon, a unit, a fixed domain, a button. The group draws the border and owns the focus ring, so the whole thing lights up as one control rather than the input lighting up inside a box.

ts
import { InputGroup, InputGroupInput, InputGroupPrefix } from "ropav";
variant
size
template
<InputGroup class="w-72">
  <InputGroupPrefix>
    <IconSearch />
  </InputGroupPrefix>
  <InputGroupInput placeholder="Anything at all" />
</InputGroup>

Prefixes and suffixes ​

input-group-affixes.vue
vue
<script setup lang="ts">
import {
  IconSearch,
  InputGroup,
  InputGroupInput,
  InputGroupPrefix,
  InputGroupSuffix,
  Label,
  TextField,
} from "ropav";
</script>

<template>
  <div class="stack">
    <TextField class="field" name="q">
      <Label>Search</Label>
      <InputGroup>
        <InputGroupPrefix>
          <IconSearch />
        </InputGroupPrefix>
        <InputGroupInput placeholder="Anything at all" />
      </InputGroup>
    </TextField>

    <TextField class="field" name="domain">
      <Label>Subdomain</Label>
      <InputGroup>
        <InputGroupInput placeholder="acme" />
        <InputGroupSuffix>.example.com</InputGroupSuffix>
      </InputGroup>
    </TextField>
  </div>
</template>

<style scoped>
.stack {
  display: flex;
  flex-direction: column;
  gap: calc(var(--rp-spacing) * 4);
}

.field {
  width: calc(var(--rp-spacing) * 72);
}
</style>

InputGroupTextArea is the multi-line member of the family, for when the companion has to sit beside something that grows.

Where the props go ​

The variant, size, full width and disabled state belong to the group, not to the input inside it — they describe the control the reader sees. The field around it still owns the value and the validation state, so is-invalid goes on the TextField.

API ​

InputGroup

PropTypeDefaultDescription
fullWidthboolean—Whether the group stretches to fill its container.
isDisabledboolean—Whether the group reads as disabled. Taken from the surrounding field when unset, which is how the field's own disabled state reaches the shell around the control.
isInvalidboolean—Whether the group reads as invalid. Taken from the surrounding field when unset.
isReadOnlyboolean—Whether the group reads as read-only. Never inherited: a field does not hand this one down, so it only ever comes from here, matching React.
size"xs" | "sm" | "md" | "lg""md"How tall the group stands, matching a button of the same size. Taken from the surrounding field when unset.
variant"primary" | "secondary""primary"Visual variant. Taken from the surrounding field when unset.

The default slot receives:

Slot propType
isDisabledboolean
isFocusVisibleboolean
isFocusWithinboolean
isHoveredboolean
isInvalidboolean

InputGroupInput

PropTypeDefaultDescription
placeholderstring—Placeholder shown while the control is empty. Declared so it can also be set here rather than only on the field; every other native attribute arrives by attribute fallthrough.
valuestring—Text in the control. Set here it takes the control over from the surrounding field, so the caller owns the value even inside a TextField — exactly as a value prop does in React. Without a listener to go with it the text is pinned.
EventPayload
changestring
update:valuestring

InputGroupPrefix

Slots: default.

InputGroupSuffix

Slots: default.

InputGroupTextArea

PropTypeDefaultDescription
placeholderstring—Placeholder shown while the control is empty. Declared so it can also be set here rather than only on the field; every other native attribute arrives by attribute fallthrough.
valuestring—Text in the control. Set here it takes the control over from the surrounding field, so the caller owns the value even inside a TextField — exactly as a value prop does in React. Without a listener to go with it the text is pinned.
EventPayload
changestring
update:valuestring