Skip to content
RTL Support: Full
Accessibility: Full
Translations: Not Needed

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.

vue
<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.

vue
<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.

3xs size
2xs size
xs size
sm size
md size
lg size
vue
<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.

Please Input
Please Input
Please Input
vue
<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.

vue
<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.

vue
<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.

vue
<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.

vue
<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.

vue
<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; returning null rejects 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.

vue
<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.

vue
<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.

kg
vue
<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.

vue
<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.

vue
<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.

vue
<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.

vue
<div class="p-[3px]">
  <!-- Your component here -->
</div>

Accessibility

  • Tie the field to its label with aria-labelledby / aria-label and surface format hints via aria-describedby.
  • Keep aria-valuemin, aria-valuemax, and aria-valuenow synchronized with the numeric value as users interact with the stepper buttons.
  • Flip aria-invalid on when users enter out-of-range values.

Imports

ts
import { HLInputNumber } from '@platform-ui/highrise'

Props

NameTypeDefaultDescription
idstringAuto (hr-input-number-*)Unique identifier for the input. When omitted an id is generated for accessibility.
valuenumber | undefinedundefinedThe input value
size'lg' | 'md' | 'sm' | 'xs' | '2xs' | '3xs''md'Size of the input
disabledbooleanfalseWhether the input is disabled
loadingbooleanfalseWhether the input is in loading state
readonlybooleanfalseWhether the input is read-only
clearablebooleanfalseWhether the input can be cleared
placeholderstring'Please Input'Placeholder text
maxnumber | undefinedundefinedMaximum allowed value
minnumber | undefinedundefinedMinimum allowed value
precisionnumber | undefinedundefinedNumber of decimal places
showButtonbooleantrueWhether to show increment/decrement buttons. Buttons are shown unless set to false.
stepnumber | undefined1Step value for increment/decrement
buttonPlacement'both' | 'right''right'Placement of increment/decrement buttons
parse(input: string) => number | null | undefinedundefinedCustom parse function for converting string input to number
format(value: number | null) => string | undefinedundefinedCustom format function for displaying the value
textAlign'start' | 'center' | 'end''start'Text alignment of the input
fontSizestring | undefinedundefinedFont size of the input
fontWeightstring | undefinedundefinedFont weight of the input

Slots

NameParametersDescription
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

NameParametersDescription
@update:value(value: number | null)Emitted when the input value changes
@input(value: number)Emitted during input with precision-rounded value
@focus() => voidFocus the input number element
@blur() => voidBlur the input number element
@clear() => voidClear the input number element

Methods

NameParametersReturnsDescription
focus() => voidvoidFocus the input number element
blur() => voidvoidBlur the input number element