Input Number
Numeric input component with optional increment/decrement buttons.
Default
A numeric input. Increment/decrement buttons are shown by default; set :show-button="false" to hide them.
<template>
<HLInputNumber v-model:value="value" id="basic-example" />
</template>
<script setup lang="ts">
import { HLInputNumber } from '@platform-ui/highrise'
import { ref } from 'vue'
const value = ref(0)
</script>Without Buttons
Set :show-button="false" to render a plain numeric field with no stepper buttons.
<template>
<HLInputNumber v-model:value="value" id="no-button-example" :show-button="false" />
</template>
<script setup lang="ts">
import { HLInputNumber } from '@platform-ui/highrise'
import { ref } from 'vue'
const value = ref(0)
</script>Sizes
The size prop accepts lg, md, sm, xs, 2xs, and 3xs.
<template>
<HLInputNumber v-model:value="value" id="size-lg" size="lg" placeholder="lg size" :show-button="true" />
<HLInputNumber v-model:value="value" id="size-md" size="md" placeholder="md size" :show-button="true" />
<HLInputNumber v-model:value="value" id="size-sm" size="sm" placeholder="sm size" :show-button="true" />
<HLInputNumber v-model:value="value" id="size-xs" size="xs" placeholder="xs size" :show-button="true" />
<HLInputNumber v-model:value="value" id="size-2xs" size="2xs" placeholder="2xs size" :show-button="true" />
<HLInputNumber v-model:value="value" id="size-3xs" size="3xs" placeholder="3xs size" :show-button="true" />
</template>
<script setup lang="ts">
import { HLInputNumber } from '@platform-ui/highrise'
import { ref } from 'vue'
const value = ref(0)
</script>Text Alignment
The text-align prop aligns the input text to start, center, or end.
<template>
<HLInputNumber v-model:value="value" id="text-align-start" text-align="start" :show-button="false" />
<HLInputNumber v-model:value="value" id="text-align-center" text-align="center" :show-button="false" />
<HLInputNumber v-model:value="value" id="text-align-end" text-align="end" :show-button="false" />
</template>
<script setup lang="ts">
import { HLInputNumber } from '@platform-ui/highrise'
import { ref } from 'vue'
const value = ref(0)
</script>With Precision
The precision prop controls the number of decimal places displayed and enforces that precision during input. When precision is set, the component will automatically round numbers to the specified number of decimal places before emitting the value. Listen to the @input event to get the rounded value as it is being typed. To get value on blur, use the @update:value event.
WARNING
While using the @input event make sure not to bind the emitted value to the input.
<template>
<HLInputNumber v-model:value="value" id="precision-example" :precision="2" :show-button="true" />
</template>
<script setup lang="ts">
import { HLInputNumber } from '@platform-ui/highrise'
import { ref } from 'vue'
const value = ref(3.14)
</script>With Min/Max Range
The min and max props constrain the value to an allowed range.
<template>
<HLInputNumber v-model:value="value" id="range-example" :min="0" :max="10" :show-button="true" />
</template>
<script setup lang="ts">
import { HLInputNumber } from '@platform-ui/highrise'
import { ref } from 'vue'
const value = ref(5)
</script>Custom Step
The step prop sets the increment/decrement amount for the buttons.
<template>
<HLInputNumber v-model:value="value" id="step-example" :step="10" :show-button="true" />
</template>
<script setup lang="ts">
import { HLInputNumber } from '@platform-ui/highrise'
import { ref } from 'vue'
const value = ref(100)
</script>Button Placement
The button-placement prop controls where the stepper buttons sit. It defaults to right (both buttons stacked on the trailing edge); set it to both to place decrement on the left and increment on the right.
<template>
<HLInputNumber v-model:value="value" id="placement-right" button-placement="right" />
<HLInputNumber v-model:value="value" id="placement-both" button-placement="both" />
</template>
<script setup lang="ts">
import { HLInputNumber } from '@platform-ui/highrise'
import { ref } from 'vue'
const value = ref(100)
</script>Clearable
Set clearable to show a clear button when the input has a value.
<template>
<HLInputNumber v-model:value="value" id="clearable-example" clearable :show-button="false" />
</template>
<script setup lang="ts">
import { HLInputNumber } from '@platform-ui/highrise'
import { ref } from 'vue'
const value = ref(5)
</script>Custom Format
format and parse decouple the input's display string from its bound numeric value. The component holds a number; these two functions convert between it and the text rendered in the field.
format(value: number | null) => string— serializes the value for display. Runs whenever the value changes (e.g.1000→"1,000").parse(input: string) => number | null— deserializes the typed text back to a number. Runs on input; returningnullrejects the entry so the value is not updated.
They must be inverses: parse(format(value)) === value. Use them when the formatting is interleaved with the digits (grouping separators, in-place symbols) and therefore cannot be expressed as a static prefix / suffix. For a fixed adornment beside the value ($, kg), prefer a prefix/suffix slot and leave the bound value as a plain number.
<template>
<HLInputNumber v-model:value="value" id="format-example" :format="formatNumber" :parse="parseNumber" :show-button="true" />
</template>
<script setup lang="ts">
import { HLInputNumber } from '@platform-ui/highrise'
import { ref } from 'vue'
const value = ref(1000)
// Add thousands separators for display: 1000 -> "1,000"
const formatNumber = (value: number | null) => {
if (value === null) return ''
return `${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')
}
// Strip the separators back to a number: "1,000" -> 1000
const parseNumber = (input: string) => {
const parsed = Number(input.replace(/[^\d.-]/g, ''))
return isNaN(parsed) ? null : parsed
}
</script>Custom Font Style
The font-size and font-weight props override the input text typography.
<template>
<HLInputNumber
v-model:value="value"
id="font-size-example"
font-size="var(--hr-font-size-4xl)"
font-weight="var(--hr-font-weight-bold)"
/>
</template>
<script setup lang="ts">
import { HLInputNumber } from '@platform-ui/highrise'
import { ref } from 'vue'
const value = ref(10)
</script>Prefix and Suffix
Use the prefix and suffix slots to place content — such as a currency symbol or a unit — inside the input, before or after the value. This content is static decoration: the user still edits the raw number, and the bound value is unchanged. To make the formatting part of the edited text instead, use format / parse.
<template>
<HLInputNumber v-model:value="value" id="prefix-example" :show-button="false">
<template #prefix><CurrencyDollarCircleIcon style="width: 1em; height: 1em;" /></template>
</HLInputNumber>
<HLInputNumber v-model:value="value" id="suffix-example" :show-button="false">
<template #suffix>kg</template>
</HLInputNumber>
</template>
<script setup lang="ts">
import { HLInputNumber } from '@platform-ui/highrise'
import { CurrencyDollarCircleIcon } from '@gohighlevel/ghl-icons/24/outline'
import { ref } from 'vue'
const value = ref(100)
</script>Custom Stepper Icons
Override the increment and decrement button icons with the add-icon and minus-icon slots.
<template>
<HLInputNumber v-model:value="value" id="custom-icons-example">
<template #add-icon><ChevronUpIcon style="width: 1em; height: 1em;" /></template>
<template #minus-icon><ChevronDownIcon style="width: 1em; height: 1em;" /></template>
</HLInputNumber>
</template>
<script setup lang="ts">
import { HLInputNumber } from '@platform-ui/highrise'
import { ChevronUpIcon, ChevronDownIcon } from '@gohighlevel/ghl-icons/24/outline'
import { ref } from 'vue'
const value = ref(100)
</script>Custom Parse with Validation
Return null from parse to reject what the user typed — the value won't update.
Here the user types a percentage. parse removes the % and returns null for anything outside 0–100, so only valid percentages are accepted.
<template>
<HLInputNumber
v-model:value="percentageValue"
id="parse-example"
:parse="parsePercentage"
:format="formatPercentage"
:min="0"
:max="100"
placeholder="Enter percentage"
:show-button="true"
/>
</template>
<script setup lang="ts">
import { HLInputNumber } from '@platform-ui/highrise'
import { ref } from 'vue'
const percentageValue = ref(50)
const parsePercentage = (input: string) => {
// Remove % symbol and whitespace
const cleaned = input.replace(/%|\s/g, '')
const parsed = Number(cleaned)
// Return null if not a valid number or out of range
if (isNaN(parsed) || parsed < 0 || parsed > 100) return null
return parsed
}
const formatPercentage = (value: number | null) => {
if (value === null) return ''
return `${value}%`
}
</script>States
The disabled, loading, and readonly props control the interactive state of the input.
<template>
<HLInputNumber id="disabled-example" disabled :value="5" :show-button="true" />
<HLInputNumber id="loading-example" loading :value="5" :show-button="true" />
<HLInputNumber id="readonly-example" readonly :value="5" :show-button="true" />
</template>
<script setup lang="ts">
import { HLInputNumber } from '@platform-ui/highrise'
</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>Accessibility
- Tie the field to its label with
aria-labelledby/aria-labeland surface format hints viaaria-describedby. - Keep
aria-valuemin,aria-valuemax, andaria-valuenowsynchronized with the numeric value as users interact with the stepper buttons. - Flip
aria-invalidon when users enter out-of-range values.
Imports
import { HLInputNumber } from '@platform-ui/highrise'Props
| Name | Type | Default | Description |
|---|---|---|---|
| id | string | Auto (hr-input-number-*) | Unique identifier for the input. When omitted an id is generated for accessibility. |
| value | number | undefined | undefined | The input value |
| size | 'lg' | 'md' | 'sm' | 'xs' | '2xs' | '3xs' | 'md' | Size of the input |
| disabled | boolean | false | Whether the input is disabled |
| loading | boolean | false | Whether the input is in loading state |
| readonly | boolean | false | Whether the input is read-only |
| clearable | boolean | false | Whether the input can be cleared |
| placeholder | string | 'Please Input' | Placeholder text |
| max | number | undefined | undefined | Maximum allowed value |
| min | number | undefined | undefined | Minimum allowed value |
| precision | number | undefined | undefined | Number of decimal places |
| showButton | boolean | true | Whether to show increment/decrement buttons. Buttons are shown unless set to false. |
| step | number | undefined | 1 | Step value for increment/decrement |
| buttonPlacement | 'both' | 'right' | 'right' | Placement of increment/decrement buttons |
| parse | (input: string) => number | null | undefined | undefined | Custom parse function for converting string input to number |
| format | (value: number | null) => string | undefined | undefined | Custom format function for displaying the value |
| textAlign | 'start' | 'center' | 'end' | 'start' | Text alignment of the input |
| fontSize | string | undefined | undefined | Font size of the input |
| fontWeight | string | undefined | undefined | Font weight of the input |
Slots
| Name | Parameters | Description |
|---|---|---|
| prefix | () | Content to be placed before the input |
| suffix | () | Content to be placed after the input |
| minus-icon | () | Custom icon for the decrement button |
| add-icon | () | Custom icon for the increment button |
Emits
| Name | Parameters | Description |
|---|---|---|
@update:value | (value: number | null) | Emitted when the input value changes |
@input | (value: number) | Emitted during input with precision-rounded value |
@focus | () => void | Focus the input number element |
@blur | () => void | Blur the input number element |
@clear | () => void | Clear the input number element |
Methods
| Name | Parameters | Returns | Description |
|---|---|---|---|
focus | () => void | void | Focus the input number element |
blur | () => void | void | Blur the input number element |