Input Group
Group multiple inputs together with various display options.
Default
Wrap an HLInputGroupLabel and an HLInput in an HLInputGroup to join them into a single seamless control.
<template>
<HLInputGroup>
<HLInputGroupLabel>https://</HLInputGroupLabel>
<HLInput id="input-group-basic-input" v-model:model-value="value" placeholder="example.com" />
</HLInputGroup>
</template>
<script setup lang="ts">
import { HLInputGroup, HLInputGroupLabel, HLInput } from '@platform-ui/highrise'
import { ref } from 'vue'
const value = ref('')
</script>Prefix and Suffix Labels
Place labels on both sides of an input to frame its value — for example a full URL.
<template>
<HLInputGroup>
<HLInputGroupLabel>https://www.</HLInputGroupLabel>
<HLInput id="input-group-affix-input" v-model:model-value="value" />
<HLInputGroupLabel>.com</HLInputGroupLabel>
</HLInputGroup>
</template>
<script setup lang="ts">
import { HLInputGroup, HLInputGroupLabel, HLInput } from '@platform-ui/highrise'
import { ref } from 'vue'
const value = ref('')
</script>Sizes
Set size on the group and it cascades to every child that doesn't set its own. The group supports six sizes: lg, md, sm (default), xs, 2xs, and 3xs.
The group sets a baseline size, and any child can opt out by setting its own. Each input, select, and label picks its size from the first of these that is set:
- Its own
sizeprop — if a child setssizedirectly, that wins. - The group's
size— otherwise the child inherits from theHLInputGrouparound it, which issmunless you set it.
INFO
A group always sets a size for its children, so a group inside an HLForm does not pick up the form's size — it stays sm until you set size on the group itself.
<template>
<HLInputGroup size="lg">
<HLInputGroupLabel>https://www.</HLInputGroupLabel>
<HLInput id="input-group-size-lg" v-model:model-value="value" />
</HLInputGroup>
<HLInputGroup size="md"><!-- … --></HLInputGroup>
<HLInputGroup size="sm"><!-- … --></HLInputGroup>
<HLInputGroup size="xs"><!-- … --></HLInputGroup>
<HLInputGroup size="2xs"><!-- … --></HLInputGroup>
<HLInputGroup size="3xs"><!-- … --></HLInputGroup>
</template>
<script setup lang="ts">
import { HLInputGroup, HLInputGroupLabel, HLInput } from '@platform-ui/highrise'
import { ref } from 'vue'
const value = ref('')
</script>Select with Input
Lead an input with a select to qualify what the user is typing. A common pattern is a scoped search — pick what to search, type the query, and trigger it with a trailing button.
<template>
<HLInputGroup style="max-width:520px">
<HLSelect id="input-group-search-scope" v-model:value="scope" :options="scopeOptions" />
<HLInput id="input-group-search-term" v-model:model-value="term" placeholder="Search…" />
<HLButton id="input-group-search-button">
<template #iconLeft><SearchLgIcon /></template>
Search
</HLButton>
</HLInputGroup>
</template>
<script setup lang="ts">
import { HLInputGroup, HLInput, HLSelect, HLButton } from '@platform-ui/highrise'
import { SearchLgIcon } from '@gohighlevel/ghl-icons/24/outline'
import { ref } from 'vue'
const scope = ref('contacts')
const term = ref('')
const scopeOptions = [
{ label: 'Contacts', value: 'contacts' },
{ label: 'Opportunities', value: 'opportunities' },
{ label: 'Conversations', value: 'conversations' },
]
</script>Select with Input Number
Pair a currency select with a number input for money fields in billing, invoicing, or product setup.
<template>
<HLInputGroup style="max-width:320px">
<HLSelect id="input-group-currency" v-model:value="currency" :options="currencyOptions" style="max-width:110px" />
<HLInputNumber id="input-group-amount" v-model:value="amount" :min="0" placeholder="0.00" />
</HLInputGroup>
</template>
<script setup lang="ts">
import { HLInputGroup, HLInputNumber, HLSelect } from '@platform-ui/highrise'
import { ref } from 'vue'
const currency = ref('usd')
const amount = ref(null)
const currencyOptions = [
{ label: 'USD', value: 'usd' },
{ label: 'EUR', value: 'eur' },
{ label: 'GBP', value: 'gbp' },
]
</script>Multiple Inputs
Combine several inputs into one seamless control — for example a first / middle / last name field.
<template>
<HLInputGroup style="max-width:600px">
<HLInput id="input-group-first-name" v-model:model-value="firstName" placeholder="First name" />
<HLInput id="input-group-middle-name" v-model:model-value="middleName" placeholder="Middle name" />
<HLInput id="input-group-last-name" v-model:model-value="lastName" placeholder="Last name" />
</HLInputGroup>
</template>
<script setup lang="ts">
import { HLInputGroup, HLInput } from '@platform-ui/highrise'
import { ref } from 'vue'
const firstName = ref('')
const middleName = ref('')
const lastName = ref('')
</script>Multiple Selects
Chain selects together for dependent choices like country and state.
<template>
<HLInputGroup style="max-width:400px">
<HLSelect id="input-group-country" v-model:value="country" :options="countryOptions" placeholder="Country" />
<HLSelect id="input-group-state" v-model:value="state" :options="stateOptions" placeholder="State" />
</HLInputGroup>
</template>
<script setup lang="ts">
import { HLInputGroup, HLSelect } from '@platform-ui/highrise'
import { ref } from 'vue'
const country = ref(null)
const state = ref(null)
const countryOptions = [
{ label: 'United States', value: 'us' },
{ label: 'Canada', value: 'ca' },
{ label: 'Mexico', value: 'mx' },
]
const stateOptions = [
{ label: 'California', value: 'ca' },
{ label: 'Texas', value: 'tx' },
{ label: 'New York', value: 'ny' },
]
</script>Input and Button
<template>
<HLInputGroup style="max-width:400px">
<HLInput id="input-group-copy-input" v-model:model-value="value" />
<HLButton id="input-group-copy-button" @click="onCopyClick"><Copy01Icon class="w-6" /> Copy</HLButton>
</HLInputGroup>
</template>
<script setup lang="ts">
import { HLInputGroup, HLInput, HLButton } from '@platform-ui/highrise'
import { Copy01Icon } from '@gohighlevel/ghl-icons/24/outline'
import { ref } from 'vue'
const value = ref('')
const onCopyClick = async () => {
await navigator.clipboard.writeText(value.value)
}
</script>Input Group with Form Validation
<template>
<HLForm>
<HLFormItem id="input-group-form" label="Website URL" validation-status="error" feedback="Enter your website URL">
<HLInputGroup>
<HLInputGroupLabel>https://www.</HLInputGroupLabel>
<HLInput id="input-group-form-input" v-model:model-value="value" />
<HLInputGroupLabel>.com</HLInputGroupLabel>
</HLInputGroup>
</HLFormItem>
</HLForm>
</template>
<script setup lang="ts">
import { HLForm, HLFormItem, HLInputGroup, HLInputGroupLabel, HLInput } from '@platform-ui/highrise'
import { ref } from 'vue'
const value = ref('')
</script>Design Guidelines
Input components use a box-shadow to render their focus ring. Box-shadows render outside the element's bounds and may be clipped by any ancestor using overflow: hidden (e.g. Tab Panels or Dropdown Menus).
To prevent this, add a small gutter padding to the component's wrapper to ensure there is enough room for the focus ring to render without being cut off.
<div class="p-[3px]">
<!-- Your component here -->
</div>- The input group stretches to fill the width of its container. Constrain it by wrapping it (or setting
max-width/widthon the group) when you need a smaller footprint. - Field elements (inputs, selects, number, phone, tag) share the available width equally — each takes an equal portion of the row and shrinks together as space tightens. Labels and buttons keep their natural, content-based width.
Accessibility
- Use a
<fieldset>/role="group"witharia-labelledbyto describe the grouped inputs. - Attach prefix/suffix explanations or error copy via
aria-describedbyon the group container. - Toggle
aria-invalidon the group when any child input fails validation so the entire control is flagged.
Imports
import { HLInputGroup, HLInputGroupLabel } from '@platform-ui/highrise'Props
HLInputGroup Props
| Name | Type | Default | Description |
|---|---|---|---|
| size | 'lg' | 'md' | 'sm' | 'xs' | '2xs' | '3xs' | 'sm' | Size of the group. Cascades to child inputs, selects, and labels that don't set their own size. |
HLInputGroupLabel Props
| Name | Type | Default | Description |
|---|---|---|---|
| size | 'lg' | 'md' | 'sm' | 'xs' | '2xs' | '3xs' | Inherits from parent | Size of the label. When unset, it inherits from the parent input group, defaulting to sm. |
Slots
HLInputGroup Slots
| Name | Parameters | Description |
|---|---|---|
| default | () | The default content slot. Can contain HLInput, HLSelect, HLButton, HLInputGroupLabel |
HLInputGroupLabel Slots
| Name | Parameters | Description |
|---|---|---|
| default | () | The default content slot for the label text |