Skip to content

BbNumberInput

The numeric field: a real number in the model, clamped to min and max.

import { BbNumberInput } from 'bitboss-ui';

On this page

Use it for

Reach for BbNumberInput whenever the value is a number somebody types: a quantity, a price, an age, a threshold, a rate limit. It cleans up what they type, clamps to min and max, and hands you a real number.

Use something else when

  • BbSlider, when a bounded value is better dragged than typed
  • BbRating, when it is a score on a fixed scale
  • BbTextInput with a mask, when the digits are an identifier: a postcode, an order number, anywhere leading zeros matter

Pass Through

Hover or tap a part to outline it. Toggles flip loading, errors and warnings when the component has them — only parts highlight.

$USDGuidance while the control is focused.

In v3, numeric text fields move from BbTextInput to BbNumberInput:

diff
- <BbTextInput v-model="quantity" type="number" label="Quantity" />
+ <BbNumberInput v-model="quantity" label="Quantity" />

The shared field props carry across; type does not.

Default

label is required, and v-model is the whole of the wiring. The model takes number | string | null and the field emits number | null. A cleared field emits null, never '' and never NaN.

Model: 8 · typeof number

label does not set name. Pass name for native form submission.

While the text is incomplete, such as - or 12., the model keeps its last parsed value.

Bounds and precision

min and max clamp the emitted value: type past the ceiling and it settles back to max. maxPrecision caps decimal places and defaults to 8. Use 0 to pin a field to whole numbers, 2 to currency.

°CBetween 16 and 28 °C, whole degrees.
°CTwo decimals. Type a third and it is dropped.

Setpoint 21 · tolerance 0.5

Clamping is silent, so state the range in hint. Commas are accepted as the decimal separator and normalized to a period.

Step controls

step (default 1) is the increment applied by ArrowUp and ArrowDown, and by the increase() / decrease() functions the slots hand you. Stepping respects min, max and maxPrecision, and does nothing while the field is disabled or readonly.

Quill Whiteboard 120×90

€179.00 each · 5 in stock

Subtotal €179.00

Every content slot receives { increase, decrease }. Give icon-only step buttons an accessible name.

step affects arrows and buttons, not typed input. Validate required multiples with errors.

Coming from v2increase() / decrease() moved to the slots

The imperative handle is gone. inputRef.value.increase() no longer exists, and a stale call is undefined at runtime rather than a compile error. Move in-field steppers to the slot scope shown above, and drive an external stepper through the model (quantity += step).

Currency, units and icons

Money and measurements want a symbol in the field and a plain number in the model. prefix and suffix render inline, either side of the typed value. prepend:icon and append:icon put an icon in the same ring.

/ unit
kg

Submitted as {"price":69,"weight":1.4}

Affixes do not change the submitted value. Format display values with Intl.NumberFormat.

The append position is contested, and by priority: clear button → spinner (loading) → error icon (hasErrors) → your append:icon. Put the decorative icon in prepend:icon, and keep append:icon for fields that are neither clearable nor validated.

Put interactive content in prepend, append, or the outer slots.

Hints, errors and warnings

Four surfaces, four jobs. description is always visible between the label and the field. hint appears below the field on focus, and persistent-hint pins it there: the right home for the range or the unit. errors renders below the field, is announced, and sets aria-invalid. warnings is its amber counterpart for a number that is valid and still worth a second look.

1 to 200 on the Team plan.

Try 12 for an error, then 180 for a warning. Both at once and only the error shows.

Non-empty messages imply their visual state. Errors win over warnings and set aria-invalid; warnings do not.

This is where a business rule lives. min and max can only express a range. A multiple, a value tied to another field, a limit that depends on the selected plan: you compute those and put them in errors.

Inside a validated form

Import the same field from bitboss-ui/validated and it takes rules, validates itself, and renders its own messages through the errors surface above.

vue
<script setup lang="ts">
import { BbButton } from 'bitboss-ui';
import { BbForm, BbNumberInput } from 'bitboss-ui/validated';
</script>

<template>
    <BbForm @submit="addLine">
        <BbNumberInput label="Quantity" :min="1" rules="required" />
        <BbButton type="submit" variant="primary">Add to order</BbButton>
    </BbForm>
</template>

The validated entrypoint needs vee-validate. Use rules for conditions that bounds do not cover, such as required; your own errors merge with rule messages.

Clearable, loading, disabled and readonly

Four props change what the field will accept, and one of them is not what it looks like.

%

clearable emits null. loading is visual only. disabled blocks all interaction, while readonly keeps the value focusable and copyable.

Label modes and density

label-mode puts the label above the field (outside, the default), resting inside it like a placeholder (floating), or pinned small at the top of the field (inside).

Leave label-mode unset to use defaultInputLabelMode. Do not pair floating with a placeholder. hide-label keeps the accessible name.

compact reduces the control height, and direction="horizontal" puts the label beside the field. Settings screens are where the pair earns its keep: each limit reads as one dense row, label left and value right.

API rate limits

Applied per key, effective immediately.

s

direction works only with the resolved outside label mode. Embedded label modes force a vertical layout.

Coming from v2floating → label-mode

A bare floating attribute was never a prop on this family. It fell through $attrs onto the root element and did nothing. The spelling is label-mode="floating". And if your stylesheets or tests target the shared input wrapper, .bb-common-input-inner-container* was renamed to .common-input-wrapper--*.