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.
Category Forms Type Web Component (<mv-number-field>) Status stable Keywords number, stepper, spinbutton, currency, percent, scrub, intl, form-associated
When to use
A bounded number like a count, percentage or price must be typed or nudged with - and + buttons The value should be displayed formatted as currency, percent or a unit while submitting the raw number Power users benefit from dragging the label to scrub the value quickly
Avoid when
It is a product quantity on a cart line or product page with stock limits → use Quantity instead The exact value matters less than a rough position within a range → use Slider instead
Get Number Field. Included in every plan: the Pro pack ships all 226 components with the CLI and the MCP server used below.
See plans
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
Name Type Default Description labelstring Built-in label (also acts as the “scrub” area). namestring Form field name (raw numeric value, e.g. “0.15”). valuenumber Initial value (also used on reset). min / maxnumber Bounds; the value is clamped and buttons disable at the limits. stepnumber 1Step (also sets the precision). large-stepnumber step × 10Step with Shift, Page↑/Page↓. formatdecimal | currency | percent | unit decimalIntl.NumberFormat style (percent: 0.15 displays as “15%”). currencystring USDISO 4217 code for format=currency. unitstring Intl unit for format=unit (kilogram, centimeter, liter…). decimalsnumber Fixed number of displayed decimals. localestring en-USFormatting and input locale (both “,” and “.” are accepted). layoutsplit | stacked split− / + on either side, or chevrons stacked on the right. wheelboolean The mouse wheel changes the value while the field has focus. scrubboolean Dragging horizontally on the label changes the value (Shift ×10, Alt ×0.1). pointer-lockboolean Locks the pointer while scrubbing (infinite drag + virtual cursor). scrub-pixelsnumber 4Pixels of movement per step. placeholderstring Text shown when empty. required / disabled / readonly / invalidboolean Form states. data-sizesm | lg Height.
Properties
Name Type Description valuenumber | null Numeric value. valueAsNumbernumber Value or NaN.
Methods
Name Description stepUp(n) / stepDown(n)Adds / removes n steps. focus()Focuses the input. checkValidity() / reportValidity()Native validation.
Events
Name Description mv-changedetail: { value, formatted } on every committed change (step, typing, scrub).
Content structure
Name Description [data-scrub]Extra child element used as a scrub area.
CSS classes
Name Description mv-number-field-label / -group / -input / -btn / -cursorGenerated parts; data-scrubbing while dragging.
CSS variables
Name Default Description --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.