Skip to content

Number Field

A component for entering and adjusting numeric values, with support for stepper buttons, keyboard interactions, locale-aware formatting, and pointer scrubbing.

Introduction

NumberField parses and formats numbers using the Intl.NumberFormat API, supporting currencies, percentages, units, and locale-specific grouping and decimal separators. When placed inside a Field, it gains labeling, validation, and state management automatically.

Anatomy

Import the parts and assemble them:

vue
<script setup>
import {
  NumberFieldDecrement,
  NumberFieldGroup,
  NumberFieldIncrement,
  NumberFieldInput,
  NumberFieldRoot,
  NumberFieldScrubArea,
  NumberFieldScrubAreaCursor,
} from 'base-ui-vue'
</script>

<template>
  <NumberFieldRoot>
    <NumberFieldScrubArea>
      <NumberFieldScrubAreaCursor />
    </NumberFieldScrubArea>
    <NumberFieldGroup>
      <NumberFieldDecrement />
      <NumberFieldInput />
      <NumberFieldIncrement />
    </NumberFieldGroup>
  </NumberFieldRoot>
</template>

Controlled value

Use the value prop together with the @value-change event to control the value:

vue
<script setup>
import {
  NumberFieldGroup,
  NumberFieldIncrement,
  NumberFieldInput,
  NumberFieldRoot,
} from 'base-ui-vue'
import { ref } from 'vue'

const amount = ref(0)
</script>

<template>
  <NumberFieldRoot :value="amount" @value-change="(next) => (amount = next)">
    <NumberFieldGroup>
      <NumberFieldInput />
      <NumberFieldIncrement />
    </NumberFieldGroup>
  </NumberFieldRoot>
</template>

Min, max, and step

Constrain the value with min and max, and control the increment amount with step. Hold Alt while stepping to use smallStep, or Shift to use largeStep.

vue
<template>
  <NumberFieldRoot :min="0" :max="100" :step="5" :default-value="20">
    <NumberFieldGroup>
      <NumberFieldDecrement />
      <NumberFieldInput />
      <NumberFieldIncrement />
    </NumberFieldGroup>
  </NumberFieldRoot>
</template>

Formatting

Pass Intl.NumberFormatOptions through the format prop and an optional locale:

vue
<template>
  <NumberFieldRoot
    :default-value="1000"
    :format="{ style: 'currency', currency: 'USD' }"
    locale="en-US"
  >
    <NumberFieldGroup>
      <NumberFieldDecrement />
      <NumberFieldInput />
      <NumberFieldIncrement />
    </NumberFieldGroup>
  </NumberFieldRoot>
</template>

Wheel scrubbing

Set allowWheelScrub to let users change the value by scrolling the wheel while the input is focused.

vue
<template>
  <NumberFieldRoot allow-wheel-scrub :default-value="0">
    <NumberFieldGroup>
      <NumberFieldInput />
    </NumberFieldGroup>
  </NumberFieldRoot>
</template>

API reference

NumberFieldRoot

Groups all parts of the number field and manages its state. Renders a <div> element.

PropTypeDefaultDescription
asstring | Component'div'The element or component to render.
valuenumber | null--The controlled raw numeric value.
defaultValuenumber--The uncontrolled value when initially rendered.
minnumber--The minimum value.
maxnumber--The maximum value.
stepnumber | 'any'1Amount to step with buttons, arrow keys, and scrubbing. Use 'any' to disable step validation.
smallStepnumber0.1Step used while holding Alt.
largeStepnumber10Step used while holding Shift.
snapOnStepbooleanfalseWhether to snap to the nearest step when stepping.
allowOutOfRangebooleanfalseWhether direct text entry may go outside min/max without clamping.
allowWheelScrubbooleanfalseWhether the value can be changed with the mouse wheel while focused.
formatIntl.NumberFormatOptions--Options used to format the value.
localeIntl.LocalesArgument--The locale used to format and parse the value.
namestring--Identifies the field when a form is submitted.
formstring--The id of the form that owns the hidden input.
idstring--The id of the input element.
requiredbooleanfalseWhether a value is required before submitting.
disabledbooleanfalseWhether the component should ignore user interaction.
readOnlybooleanfalseWhether the user is unable to change the value.
classstring | ((state: State) => string)--CSS class, or a function returning a class based on state.
styleStyleValue | ((state: State) => StyleValue)--Style, or a function returning a style based on state.
EventTypeDescription
@value-change(value: number | null, eventDetails) => voidFired when the value changes.
@value-committed(value: number | null, eventDetails) => voidFired when the value is committed (blur, pointer release, or keyboard).
Data attributeDescription
data-disabledPresent when disabled.
data-readonlyPresent when read-only.
data-requiredPresent when required.
data-scrubbingPresent while scrubbing.
data-validPresent when the field is valid.
data-invalidPresent when the field is invalid.
data-touchedPresent when the field has been touched.
data-dirtyPresent when the value has changed.
data-filledPresent when the field contains a value.
data-focusedPresent when the field is focused.

NumberFieldGroup

Groups the input with the increment and decrement buttons. Renders a <div> element with role="group".

PropTypeDefaultDescription
asstring | Component'div'The element or component to render.
classstring | ((state: State) => string)--CSS class, or a function returning a class based on state.
styleStyleValue | ((state: State) => StyleValue)--Style, or a function returning a style based on state.

NumberFieldInput

The native input control. Renders an <input> element.

PropTypeDefaultDescription
asstring | Component'input'The element or component to render.
classstring | ((state: State) => string)--CSS class, or a function returning a class based on state.
styleStyleValue | ((state: State) => StyleValue)--Style, or a function returning a style based on state.

NumberFieldIncrement

A stepper button that increases the value. Renders a <button> element.

PropTypeDefaultDescription
asstring | Component'button'The element or component to render.
disabledbooleanfalseWhether the button is disabled.
nativeButtonbooleantrueWhether the rendered element is a native <button>.
classstring | ((state: State) => string)--CSS class, or a function returning a class based on state.
styleStyleValue | ((state: State) => StyleValue)--Style, or a function returning a style based on state.

NumberFieldDecrement

A stepper button that decreases the value. Renders a <button> element.

PropTypeDefaultDescription
asstring | Component'button'The element or component to render.
disabledbooleanfalseWhether the button is disabled.
nativeButtonbooleantrueWhether the rendered element is a native <button>.
classstring | ((state: State) => string)--CSS class, or a function returning a class based on state.
styleStyleValue | ((state: State) => StyleValue)--Style, or a function returning a style based on state.

NumberFieldScrubArea

An interactive area where the user can click and drag to change the value. Renders a <span> element.

PropTypeDefaultDescription
asstring | Component'span'The element or component to render.
direction'horizontal' | 'vertical''horizontal'Cursor movement direction.
pixelSensitivitynumber2Pixels the cursor must move before the value changes.
teleportDistancenumber--Distance the cursor may move from center before looping back.
classstring | ((state: State) => string)--CSS class, or a function returning a class based on state.
styleStyleValue | ((state: State) => StyleValue)--Style, or a function returning a style based on state.

NumberFieldScrubAreaCursor

A custom element shown instead of the native cursor while scrubbing. Renders a <span> element. Uses the Pointer Lock API and is disabled in Safari.

PropTypeDefaultDescription
asstring | Component'span'The element or component to render.
classstring | ((state: State) => string)--CSS class, or a function returning a class based on state.
styleStyleValue | ((state: State) => StyleValue)--Style, or a function returning a style based on state.