Skip to content

BbNumberInput

Captures and validates numeric form values, emits a number value.

import { BbNumberInput } from 'bitboss-ui';

On this page

Props

NameDescription
append:icon Type: string

Name of the icon to be added at the end of the input.

The append position is contested, by priority: clear button → spinner (loading) → error icon (hasErrors) → this. On a clearable or validatable field your icon is the first thing displaced, so prefer prepend:icon for decoration.

See example
autocomplete Type: stringDefault"off"

Guides the browser as to the type of information expected in the field.

autofocus Type: Booleanish

Focuses the field when it mounts (a dialog already open included), unless the user is typing in another field.

clearable Type: booleanDefaultfalse

Displays a clear button when the input has a value and is being interacted with.

Emits null, not 0 or ''. Suppressed on disabled and readonly fields, and it takes the append position from append:icon.

See example
compact Type: booleanDefaultfalse

Compact density: the field uses the -compact twins of --bb-input-h, --bb-input-py and --bb-label-spacing-y, so a --bb-input-h set on the component is ignored while it is on. Size a compact field with --bb-input-h-compact (and --bb-input-py-compact).

The only density knob: this family has no size scale. Set it per view rather than per field, so a form does not mix two control heights.

See example
currency Type: string

An ISO 4217 code ('EUR'): the amount shows the locale's way, symbol inside the text (1.234,56 €), leaving #prefix / #suffix free; the model is the number. Decimals default to the currency's; minPrecision / maxPrecision win. Not with unit.

Puts the symbol inside the text, where the locale writes it (€69.00 in English, 69,00 € in Italian), and sets the decimals unless minPrecision / maxPrecision are set. The model stays the number. A maxlength and event.target.value see the symbol too.

See example
description Type: string

Text between the label and the input. Unlike the hint it is always visible; it joins the input's aria-describedby after any errors / warnings, before the hint.

For what the user needs before typing. Anything about the acceptable range reads better in hint, next to the field they are about to get wrong.

See example
disabled Type: booleanDefaultfalse

Disables the component.

Blocks everything, arrow-key stepping included. For a number that is derived or detected rather than forbidden, readonly keeps it legible and copyable.

See example
disableFormatting Type: booleanDefaultfalse

Shows the number as typed (period decimal, no grouping), with name on the visible input. Without it the field formats the locale's way while typing (10.005,6) and posts the raw value (10005.6) through a hidden input carrying name.

Shows the number as typed, with a period decimal and no grouping, and puts name back on the visible input. currency and unit are ignored. For code that cannot cope with the formatted text yet; the default is what users should see.

See example
errors Type: string | string[]

Error messages under the field, a string or array, in an aria-live="polite" region and first in the control's aria-describedby, so they are re-read when it regains focus.

Where a business rule lives, since min and max can only express a range and do it without a message. Non-empty is enough; hasErrors is only for when the message itself is elsewhere. Inside a BbForm these merge with the rule messages rather than replacing them.

See example
formless Type: booleanDefaultfalse

Keep this control out of the enclosing BbForm entirely: not submitted, not dirty, not reset, not validated. For a control that is not form data (a filter, a "show advanced" switch).

hasErrors Type: booleanDefaultfalse

Define if the component should be in an error state. It usually attaches a CSS class for styling purposes.

Forces the error chrome without a message of its own. Reach for it when the text lives in a summary alert above the form.

See example
hasWarnings Type: booleanDefaultfalse

Define if the component should be in a warning state. Same chrome as errors with --bb-warn; errors take priority.

The amber counterpart of hasErrors, and equally a force-the-chrome flag. It never sets aria-invalid: a warning says "unusual", not "wrong".

See example
hideLabel Type: booleanDefaultfalse

Visually hides the label of the input while maintaining accessibility.

hint Type: string

Text box to be displayed near the input, usually to indicate instructions.

The natural home for the range or the unit, because min and max correct a value in silence. Pair with persistentHint when the range matters before focus, not just during it.

See example
id Type: string

The id of the native control; the label's for and the description and message ids derive from it. Generated when omitted.

inputAlign Type: FieldCrossAlign

Vertical position of the control in a side-by-side row; not inputPosition, the horizontal one. Omitted, the control's first line meets the label's.

label requiredType: string

Text content of the label of the element.

Names the field for display and for assistive technology only. It does not set name. Inside a BbForm, a field with no name joins under a slug of this text; pass name for a clean key.

See example
labelAlign Type: FieldCrossAlign

Vertical position of the label block in a side-by-side row; not labelPosition, the horizontal one. Omitted, the label's first line meets the control's.

labelMode Type: "outside" | "floating" | "inside"

Label rendering mode.

Unset, it falls back to the project-wide defaultInputLabelMode, so a product can go all-floating from the plugin config without touching call sites. Do not pair floating with a placeholder: the resting label already occupies that spot.

See example
labelPosition Type: "left" | "center" | "right"

Sets the text alignment of the label.

layout Type: Responsive<FieldLayout>

How label and input sit together: 'vertical', 'horizontal' (50/50), 'auto', 'label-fill', 'input-fill', a ratio like 'xx xxxxx', or a per-breakpoint map ({ default: 'vertical', md: 'xx xxxxx' }).

Ignored, without a warning, unless the resolved label mode is outside. floating and inside embed the label in the field and force the vertical layout, including when the mode comes from defaultInputLabelMode rather than from the call site.

See example
loading Type: booleanDefaultfalse

Sets the component in a loading state, usually triggering some visual styles.

Visual only. The field stays editable underneath the spinner, so if an async check has to settle before the value is usable, guard that yourself.

See example
max Type: numberDefaultNumber.MAX_SAFE_INTEGER

Maximum value cap.

Clamps the emitted value at once, with no message and no event, so a user who types past it sees their number change under them. Say the ceiling in hint before they reach it.

See example
maxPrecision Type: numberDefault8

Maximum precision of the number: fraction digits past it are refused as typed (never rounded). With currency, the currency's own digits (2 for EUR, 0 for JPY, 3 for KWD), or minPrecision when that is larger.

0 pins the field to whole numbers; for money set currency, which brings its own decimals. Extra decimals are refused as typed, never rounded: with 0 a typed , or . stays until blur and the digits after it are refused (12,5 is 12, not 125). Below 3, a second , or . is refused once a decimal exists.

See example
min Type: numberDefaultNumber.MIN_SAFE_INTEGER

Minimum value cap. Applied on blur and on Enter (before a surrounding form submits), not while typing, so a value above a min greater than 1 can be typed digit by digit.

Applied when the field loses focus or on Enter, not per keystroke, so 20 can be typed into a 16–28 field; left below it, the value rises to min. Enter applies it before a surrounding form submits, which makes a min_value rule inside a BbForm redundant.

See example
minPrecision Type: numberDefault0

Fraction digits always shown (2: 1 shows 1,00), also while typing, where the padding zeros are placeholders; the model stays the number. Above maxPrecision it gives way. Applies with disableFormatting too. With currency: the currency's own digits.

Decimals always shown, padded with zeros the user types over: with 2, 1 shows 1.00 while the model stays 1. Also the way to keep trailing zeros after blur, which otherwise rewrites 1.50 as 1.5.

See example
modelValue Type: string | number | nullDefaultnull

Used by v-model.

Accepts number | string | null and emits number | null. A cleared field emits null, never '' and never NaN, and an in-progress string (-, ., 12.) emits nothing until it parses.

See example
name Type: string

Defines the name of the input.

Not derived from label. It lands on a hidden input that posts the raw value (10005.6), never on the visible one, so input[name=…] finds the hidden input: a test types into input[role="spinbutton"]. Leave it unset and a native post or a FormData read drops the value.

See example
persistentHint Type: booleanDefaultfalse

Keeps the hint displayed.

placeholder Type: string

Text shown while the field is empty.

prepend:icon Type: string

Name of the icon to be added at the start of the input.

The uncontested position: nothing in the component competes for it. Put decorative iconography here and keep append:icon for fields that are neither clearable nor validatable.

See example
pt Type: (PtMap<TextControlPtPart, FormControlPtState> & { "root:outline"?: PtValue | undefined; "icon:outline"?: PtValue | undefined; "root:secondary"?: PtValue | undefined; "icon:secondary"?: PtValue | undefined; "spinner:outline"?: PtValue | undefined; "spinner:secondary"?: PtValue | undefined; "clear:outline"?: PtValue | undefined; "clear:secondary"?: PtValue | undefined; "root:ghost"?: PtValue | undefined; "icon:ghost"?: PtValue | undefined; "spinner:ghost"?: PtValue | undefined; "clear:ghost"?: PtValue | undefined; "label:outline"?: PtValue | undefined; "label:secondary"?: PtValue | undefined; "label:ghost"?: PtValue | undefined; "description:outline"?: PtValue | undefined; "description:secondary"?: PtValue | undefined; "description:ghost"?: PtValue | undefined; "message:outline"?: PtValue | undefined; "message:secondary"?: PtValue | undefined; "message:ghost"?: PtValue | undefined; "hint:outline"?: PtValue | undefined; "hint:secondary"?: PtValue | undefined; "hint:ghost"?: PtValue | undefined; "input:outline"?: PtValue | undefined; "input:secondary"?: PtValue | undefined; "input:ghost"?: PtValue | undefined; "box:outline"?: PtValue | undefined; "box:secondary"?: PtValue | undefined; "box:ghost"?: PtValue | undefined; "prefix:outline"?: PtValue | undefined; "prefix:secondary"?: PtValue | undefined; "prefix:ghost"?: PtValue | undefined; "suffix:outline"?: PtValue | undefined; "suffix:secondary"?: PtValue | undefined; "suffix:ghost"?: PtValue | undefined; })

Passthrough, object form: { box: '…', 'box:errors': '…' } — the same keys as the pt:* attributes without the prefix. See the pt:<part> row.

pt:<part> Type: PtValue

Passthrough, attribute form: one attribute per part, pt:<part>, and per part and state, pt:<part>:<state>. Parts: box, clear, description, hint, icon, input, label, message, prefix, root, spinner, suffix. States: disabled, errors, ghost, hasValue, loading, outline, readonly, secondary, warnings.

See example
readonly Type: booleanDefaultfalse

Sets the input in a readonly state.

The right state for a number that is computed or detected rather than entered, such as a total or a weight read off a scale. Unlike disabled it stays legible and copyable, and it disables stepping just the same.

See example
required Type: booleanDefaultfalse

Marks the input required (asterisk, aria-required, native validation in a plain form). Inside a BbForm it is not enforced; use rules="required" or the schema.

Forwards to the native input and validates nothing on its own. It raises the required marker (unless requiredAsterisk is off); inside a BbForm a required rule or the schema does too, and checks the value.

reverse Type: booleanDefaultfalse

Reverses the layout. Applicable in every direction the order of the label and the input is swapped.

rules Type: RuleExpression<string | number | null>

vee-validate rules for this field. Only inside a BbForm.

Read only inside a BbForm (which needs the vee-validate peer); outside one they do nothing. Spend rules on what min/max cannot say: min lifts a low value on blur and on Enter, before the form submits, so a min_value rule is redundant.

See example
step Type: numberDefault1

Incremental unit used by ArrowUp / ArrowDown and by the increase and decrease functions the slots receive. It is NOT applied to manual input as a step of 5 would prevent the user from inserting a value like 115 because of rounding down.

Drives ArrowUp/ArrowDown and the increase/decrease slot functions, and never constrains typed input. If multiples are a real rule, enforce them through errors on blur or on submit.

See example
unit Type: BbNumberUnit

A unit Intl.NumberFormat knows ('kilogram', 'celsius', 'percent'), shown the locale's way inside the text (20 kg). The model is the number you see: percent showing 15 % holds 15. Not with currency (which wins).

Typed: only units Intl.NumberFormat knows, so kilowatt is a type error. percent holds the number you see, 15% is 15, not 0.15. With currency also set, currency wins.

See example
validationLabel Type: string

The field's name in validation messages ({field}): "Email is not valid". Defaults to the label (or legend), then "This field"; never the name. Set it when the label is hidden or reads badly in a sentence (icon-only, a question). BbForm only.

validationMode Type: ValidationMode

When the field validates: aggressive (each change), balanced (on leave, then live while in error), lazy (on leave), submit-only, submit-live. Unset: the BbForm's validation-mode, then formControls.validationMode ('balanced'). BbForm only.

See example
variant Type: InputVariantTypeDefault'outline'

The field box's look, with BbButton's names and tokens. Colours only, so a form never reflows; 'ghost' has no border in any state, 'none' no look at all (you own hover, focus and the states). Register more with the plugin's inputVariants.

warnings Type: string | string[]

Warning messages under the field, a string or array: amber, in their own aria-live region and in the control's aria-describedby after the errors. Non-empty turns on the warning state; errors win when both are set.

For a number that is valid and still worth a second look. Errors win when both are set and the warnings are suppressed, so the field is never amber and red at once.

See example

v-model

Values kept in sync through v-model.

NameDescription
modelValue Type: string | number | null

Seed it with null for an empty field rather than 0: 0 is a number someone chose, and on a floating label it also stops the label from resting inside the field.

See example

Events

NameDescription
blur Type: (event: FocusEvent): void

Emitted when the native input loses focus. Forwards the original DOM FocusEvent.

change Type: (event: Event): void

Emitted when the native input fires a change event. Forwards the original DOM Event.

click Type: (event: MouseEvent): void

Emitted when the input receives a click interaction. Forwards the original DOM MouseEvent.

compositionend Type: (event: CompositionEvent): void

Emitted when a composition session ends (e.g. CJK IME confirmed). Forwards the original DOM CompositionEvent.

compositionstart Type: (event: CompositionEvent): void

Emitted when a composition session starts (e.g. CJK IME begins). Forwards the original DOM CompositionEvent.

decrease Type: (value: number): void

Emitted by the decrease helper with the clamped value after decrementing by one step.

See example
focus Type: (event: FocusEvent): void

Emitted when the native input gains focus. Forwards the original DOM FocusEvent.

increase Type: (value: number): void

Emitted by the increase helper with the clamped value after incrementing by one step.

Fires with the new, already clamped number, alongside update:modelValue. It is for reacting to a step, not for reading the value; v-model already has that.

See example
input Type: (event: Event): void

Emitted on native input events from the number input. Forwards the original DOM Event.

event.target.value is the text on screen, grouped and with any symbol (€1,234.50), not the number. Read the number from v-model.

See example
keydown Type: (event: KeyboardEvent): void

Emitted for keyboard interaction on the input. Forwards the original DOM KeyboardEvent.

keyup Type: (event: KeyboardEvent): void

Emitted when a key is released over the input. Forwards the original DOM KeyboardEvent.

mousedown Type: (event: MouseEvent): void

Emitted when a pointing device button is pressed over the input. Forwards the original DOM MouseEvent.

mouseup Type: (event: MouseEvent): void

Emitted when a pointing device button is released over the input. Forwards the original DOM MouseEvent.

paste Type: (event: ClipboardEvent): void

Emitted when content is pasted into the input. Forwards the original DOM ClipboardEvent.

Forwarded as is. The field already reads a paste as a number (the first one in the text, symbols and words dropped, brackets negative), so a handler never needs to clean the clipboard text.

See example
update:modelValue Type: (value: number | null): void

Emitted on any value change with the parsed number or null when the field is empty.

Emits number | null. Do not add a watcher that re-parses or re-clamps what arrives here: the component has already done both.

See example

Slots

The listed properties are the ones exposed to the slot scope.

NameDescription
append Type: BbNumberInputStepSlotProps

Content rendered after the number input, at the end of the inner container. Typically used to place increment/decrement buttons next to the input.

Same { increase, decrease } scope as prepend, and the same accessible-name obligation.

See example
append:outer Type: BbNumberInputStepSlotProps

Content rendered after the entire input control, outside the input chrome.

The uncontested place for an action beside the field, since nothing inside the component competes for it.

description Type: BbNumberInputDescriptionSlotProps

Replaces the description text. Provided alone (no description prop) it still renders the description region and wires it into aria-describedby.

label Type: BbNumberInputLabelSlotProps

Replaces the default label text rendered above the number input.

Receives { text, hasErrors, hasWarnings }, plus showAsterisk while the required marker shows. Replacing it removes the marker the control drew, so put it back with <BbAsterisk v-if="showAsterisk" />, or unconditionally on a required field in an app that turned requiredAsterisk off.

See example
prefix Type: BbNumberInputStepSlotProps

Inline content rendered at the start of the input field area, before the typed number.

Decoration only, inside the field. Not for a currency symbol: currency places that where the locale writes it, before or after the number.

See example
prepend Type: BbNumberInputStepSlotProps

Content rendered before the number input, at the start of the inner container.

Receives { increase, decrease }, which is how a minus button is built with no state on your side. It is icon-only, so give it an aria-label.

See example
prepend:outer Type: BbNumberInputStepSlotProps

Content rendered before the entire input control, outside the input chrome.

Outside the field chrome entirely. Reach for it when a stepper button should not sit inside the border, or when the append position is already taken by a clear button or a spinner.

suffix Type: BbNumberInputStepSlotProps

Inline content rendered at the end of the input field area, after the typed number.

Inert, like prefix, so anything interactive goes in prepend/append or the outer pair. A unit the locale can write (kg, °C, %) reads better through unit.

See example

Renamed and removed

Names from v2 and from earlier 3.0 betas that no longer work, and what to write instead.

  • slotappend-outerappend:outerfails silently
  • directionlayoutfails silently
  • hasWarninghasWarningsfails silently
  • slotprepend-outerprepend:outerfails silently
  • validateOnvalidationModefails silently

    An array of events became one mode (aggressive | balanced | lazy | submit-only | submit-live). The old defaults (['blur'], ['inactive'], a toggle's ['update:modelValue', 'change', 'blur']) are balanced, the new default: delete the prop. A text field on ['update:modelValue'] is validation-mode="aggressive". Set it once on <BbForm validation-mode> instead of per field.

  • vidremovedfails silently

    A display name (v2: vid="Email address") is now validation-label; a field path (3.0 betas: vid="address.city") is now name (brackets for a native post: address[city]). check --fix picks by the value.