Skip to content

NumberField

The NumberField family provides a headless numeric control with pointer scrubbing, mixed values, keyboard stepping, safe arithmetic expressions, units, trailing actions, and binding-aware state.

Interactive anatomy

Try +10, *2, 50%, or 12*8+4

W24px R M

Mixed

Mixed

Disabled

16

Bound

8gap/md

Anatomy

  • NumberFieldRoot — renderless state and interaction owner
  • NumberFieldLeading — leading label or icon
  • NumberFieldValue — non-editing value
  • NumberFieldInput — editing input with spinbutton semantics
  • NumberFieldUnit — unit text
  • NumberFieldTrailing — trailing action area
  • NumberFieldMenu — field menu area

Root slot

The default slot receives modelValue, displayValue, draftValue, placeholder, all state booleans, state, actions, and attrs. Bind attrs to the focusable outer element. It contains the canonical spinbutton ARIA contract, keyboard/focus handlers, and data-editing, data-scrubbing, data-mixed, data-disabled, and data-bound attributes.

Expressions and keyboard

Committed input accepts absolute arithmetic such as 12*8+4, relative operations such as +10, -4, *2, and /3, and percentages such as 50% when max is finite. The parser only accepts numbers, parentheses, and + - * /; it never evaluates JavaScript.

Arrow keys step by step. Shift multiplies the step by 10 and Alt multiplies it by 0.1. Enter commits and Escape restores the interaction-start value.

Example

vue
<script setup lang="ts">
import { 
ref
} from 'vue'
import {
NumberFieldInput
,
NumberFieldLeading
,
NumberFieldRoot
,
NumberFieldUnit
,
NumberFieldValue
} from '@open-pencil/vue' const
width
=
ref
(120)
</script> <template> <
NumberFieldRoot
v-slot="{
attrs
,
editing
,
actions
}"
v-model
="
width
"
:min
="0"
:max
="1000"
aria-label="Width" > <
div
v-bind="
attrs
" @
pointerdown
="!
editing
&&
actions
.startScrub(
$event
)">
<
NumberFieldLeading
>W</NumberFieldLeading>
<
NumberFieldInput
/>
<
NumberFieldValue
/>
<
NumberFieldUnit
>px</NumberFieldUnit>
</
div
>
</NumberFieldRoot> </template>

Generated API reference

The following tables are extracted from the Vue source and its JSDoc during the documentation build.

NumberFieldRoot

Generated from packages/vue/src/primitives/NumberField/NumberFieldRoot.vue

Props

PropDefaultType
modelValue*
Current numeric value or the mixed-value sentinel.
number | symbol
min
Minimum allowed value.
-Infinitynumber | undefined
max
Maximum allowed value and percentage-expression basis.
Infinitynumber | undefined
step
Pointer-scrub and Arrow-key increment.
1number | undefined
sensitivity
Multiplier applied to pointer-scrub movement.
1number | undefined
placeholder
Text shown when modelValue is mixed.
"Mixed"string | undefined
ariaLabel
Accessible name for the spinbutton.
string | undefined
disabled
Prevents editing, scrubbing, and keyboard stepping.
boolean | undefined
bound
Marks the value as controlled by an external binding.
boolean | undefined
editPolicy
Mutation policy used when the value is bound.
"editable"NumberFieldEditPolicy | undefined

Events

EventPayloadDescription
update:modelValue[value: number]
editing-change[editing: boolean]
commit[value: number, previous: number]
invalid[expression: string, reason: NumberExpressionError]
detach-request[source: NumberFieldMutationSource]

Slots

SlotPropsDescription
default
Complete render contract for composing a numeric field.
NumberFieldSlotPropsComplete render contract for composing a numeric field.

NumberFieldInput

Generated from packages/vue/src/primitives/NumberField/NumberFieldInput.vue

No component-specific props, events, slots, or exposed members.

NumberFieldValue

Generated from packages/vue/src/primitives/NumberField/NumberFieldValue.vue

Slots

SlotPropsDescription
default
Non-editing display value plus the complete field render contract.
NumberFieldSlotProps & { value: string; }Non-editing display value plus the complete field render contract.

Released under the MIT License.