Number Field — <mv-number-field>

Numeric input with − / + buttons (press and hold to accelerate), bounds and step, arrow keys and mouse wheel, Intl formatting (currency, percent, unit) and a “scrub” label: drag horizontally to change the value, with optional pointer lock.

CategoryForms
TypeWeb Component (<mv-number-field>)
Statusstable
Keywordsnumber, stepper, spinbutton, currency, percent, scrub, intl, form-associated

When to use

Avoid when

Install

node scripts/add.mjs number-field --out ./src/marvelous

AI agent with the Marvelous UI MCP server: install_components({ slugs: ["number-field"], target_dir: "<absolute path>/src/marvelous", framework: "react" }).

Files copied (dependencies included): tokens/tokens.css, core/base.css, core/dom.js, core/element.js, core/motion.js, components/number-field/number-field.js, components/number-field/number-field.css.

Usage

Canonical markup — start from it and customize with attributes, data-* and CSS variables:

<form id="number-field-demo-form" style="display:grid;grid-template-columns:repeat(2,minmax(0,10.5rem));gap:1.25rem 1.5rem;justify-content:center">
  <mv-number-field label="Quantity" name="quantity" value="2" min="1" max="20" style="--mv-number-field-width:100%"></mv-number-field>
  <mv-number-field label="Unit price" name="price" value="24.9" min="0" step="0.5" format="currency" currency="USD" wheel style="--mv-number-field-width:100%"></mv-number-field>
  <mv-number-field label="Discount" name="discount" value="0.15" min="0" max="0.5" step="0.05" format="percent" layout="stacked" style="--mv-number-field-width:100%"></mv-number-field>
  <mv-number-field id="number-field-demo-weight" label="Weight" name="weight" value="2.4" min="0" max="30" step="0.1" format="unit" unit="kilogram" scrub pointer-lock style="--mv-number-field-width:100%"></mv-number-field>
  <p style="grid-column:1/-1;margin:0;text-align:center;font-size:.75rem;color:var(--mv-fg-muted)">Hold − / + to repeat · ↑/↓ on the keyboard (Shift ×10) · drag the “Weight” label horizontally.</p>
</form>

API

Attributes

NameTypeDefaultDescription
labelstringBuilt-in label (also acts as the “scrub” area).
namestringForm field name (raw numeric value, e.g. “0.15”).
valuenumberInitial value (also used on reset).
min / maxnumberBounds; the value is clamped and buttons disable at the limits.
stepnumber1Step (also sets the precision).
large-stepnumberstep × 10Step with Shift, Page↑/Page↓.
formatdecimal | currency | percent | unitdecimalIntl.NumberFormat style (percent: 0.15 displays as “15%”).
currencystringUSDISO 4217 code for format=currency.
unitstringIntl unit for format=unit (kilogram, centimeter, liter…).
decimalsnumberFixed number of displayed decimals.
localestringen-USFormatting and input locale (both “,” and “.” are accepted).
layoutsplit | stackedsplit− / + on either side, or chevrons stacked on the right.
wheelbooleanThe mouse wheel changes the value while the field has focus.
scrubbooleanDragging horizontally on the label changes the value (Shift ×10, Alt ×0.1).
pointer-lockbooleanLocks the pointer while scrubbing (infinite drag + virtual cursor).
scrub-pixelsnumber4Pixels of movement per step.
placeholderstringText shown when empty.
required / disabled / readonly / invalidbooleanForm states.
data-sizesm | lgHeight.

Properties

NameTypeDescription
valuenumber | nullNumeric value.
valueAsNumbernumberValue or NaN.

Methods

NameDescription
stepUp(n) / stepDown(n)Adds / removes n steps.
focus()Focuses the input.
checkValidity() / reportValidity()Native validation.

Events

NameDescription
mv-changedetail: { value, formatted } on every committed change (step, typing, scrub).

Content structure

NameDescription
[data-scrub]Extra child element used as a scrub area.

CSS classes

NameDescription
mv-number-field-label / -group / -input / -btn / -cursorGenerated parts; data-scrubbing while dragging.

CSS variables

NameDefaultDescription
--mv-number-field-width9.5remWidth.
--mv-number-field-radiusvar(--mv-radius-md)Group radius.

Accessibility

APG Spinbutton pattern: the input has role=spinbutton, aria-valuenow, aria-valuetext (formatted value, e.g. “$24.90”), aria-valuemin/max, and the name of the built-in or associated <label>. ↑/↓ (Shift ×10), Page↑/↓, Home/End (bounds), Enter commits, Escape cancels typing. The −/+ buttons are out of the tab order (tabindex=-1) and labeled “Decrease” / “Increase”. Scrubbing is a pointer shortcut, never the only way to change the value.