Skip to content

InputNumber ​

InputNumber is a numeric field built on reka-ui's number field. It emits a number | null model, supports min / max / step / integer, and formats its value with Intl.NumberFormat (including currency and percent styles). Optional stepper buttons provide pointer-driven increments.

vue
<script setup lang="ts">
import { ref } from 'vue'
import { InputNumber } from '@myghf/ui'

const quantity = ref<number | null>(1)
</script>

<template>
  <InputNumber v-model="quantity" :min="0" :max="10" show-buttons />
</template>

Examples ​

Bounds and stepper buttons ​

modelValue is number | null. Clearing the field (or entering a non-numeric value) emits null rather than NaN. showButtons adds keyboard-accessible increment and decrement controls.

vue
<script setup lang="ts">
import { ref } from 'vue'
import { InputNumber } from '@myghf/ui'

const quantity = ref<number | null>(3)
</script>

<template>
  <div class="grid max-w-xs gap-4">
    <div class="grid gap-1.5">
      <label class="text-sm font-medium text-foreground" for="demo-quantity">Quantity</label>
      <InputNumber
        id="demo-quantity"
        v-model="quantity"
        :min="0"
        :max="10"
        show-buttons
      />
    </div>

    <InputNumber
      v-model="quantity"
      placeholder="Empty is null"
      aria-label="Quantity without stepper buttons"
    />
  </div>
</template>

Formatting ​

currency is shorthand for a currency Intl.NumberFormatOptions; formatOptions supplies the full options object (here a percent style); locale selects the format locale. stepSnapping rounds typed values to the nearest step.

kg
vue
<script setup lang="ts">
import { ref } from 'vue'
import { InputNumber } from '@myghf/ui'

const price = ref<number | null>(1250.5)
const ratio = ref<number | null>(0.75)
const weight = ref<number | null>(72.5)
</script>

<template>
  <div class="grid max-w-xs gap-4">
    <InputNumber v-model="price" currency="USD" locale="en-US" :min="0" aria-label="Price" />

    <InputNumber
      v-model="ratio"
      locale="en-US"
      :format-options="{ style: 'percent', maximumFractionDigits: 0 }"
      aria-label="Ratio"
    />

    <InputNumber
      v-model="weight"
      :step="0.25"
      step-snapping
      :min="0"
      suffix="kg"
      aria-label="Weight"
    />
  </div>
</template>

Props ​

PropTypeDefaultDescription
modelValuenumber | null—Bound numeric value; null when empty.
minnumber—Minimum allowed value.
maxnumber—Maximum allowed value.
stepnumber1Increment/decrement size. A non-positive or non-finite value is normalised to 1 before it reaches the field.
stepSnappingbooleanfalseRounds typed values to the nearest multiple of step.
integerbooleanfalseForces zero fraction digits (maximumFractionDigits: 0).
localestring—BCP-47 locale for Intl.NumberFormat, and for the aria-valuetext readout.
formatOptionsIntl.NumberFormatOptions—Full formatting options; merged over the currency shorthand, and integer is applied last.
currencystring—Currency code (for example 'USD'); applies { style: 'currency' }.
prefixstring—Decorative text rendered before the number (for example '$').
suffixstring—Decorative text rendered after the number (for example 'kg').
showButtonsbooleanfalseRenders increment/decrement stepper buttons.
placeholderstring—Placeholder text shown while empty.
disabledbooleanfalseDisables the control.
readonlybooleanfalseMakes the value read-only while still focusable.
invalidbooleanfalseApplies the error styling and sets aria-invalid="true" on the input.
size'sm' | 'default' | 'lg''default'Control height.
idstring—Applied to the underlying input, so an external <label for> matches.
namestring—Form field name for the underlying input.

Events ​

EventPayloadDescription
update:modelValuenumber | nullEmitted when the value changes. Empty or non-finite input collapses to null.

Slots ​

InputNumber renders no slots. Use prefix / suffix for fixed adornments.

Exposed methods ​

None. InputNumber does not call defineExpose.

Accessibility ​

  • The underlying field is a native input with role="spinbutton", so screen readers announce it as a numeric control with arrow-key support from reka-ui.
  • invalid sets aria-invalid="true" on the input automatically.
  • When a value is present, the input exposes a locale-formatted aria-valuetext (for example 1,234.5), so Intl formatting is announced rather than the raw string. It is omitted when the field is empty.
  • prefix and suffix are plain sibling text, not part of the input. A screen reader may read them as loose text without associating them with the value. For a real unit, prefer currency / formatOptions (which feed aria-valuetext) or include the unit in the field's <label>.
  • The stepper buttons rendered by showButtons come from reka-ui and are keyboard reachable; they are disabled automatically at min / max.

Dark mode & RTL ​

  • The wrapper uses semantic tokens (bg-surface, text-foreground, border-border) and the invalid state uses error-500, so both themes are covered without dark: overrides.
  • prefix and suffix sit in a flex row and the stepper column uses logical margin (ms-1), so the layout mirrors under RTL. The prefix/suffix text is direction-neutral; numbers themselves are rendered left-to-right by Intl regardless of direction.

Released under the MIT License.