Quantity field

A 44px Vlak numeric input and styled unit selector with controlled quantity values, form submission and reset support.

Sample volume
Unit

Prepare the record

Aliquot / Sample 042

Recorded volume

Change the unit to express the same entered volume

Unit

Use it for

  • Dimensioned quantities with explicit unit choices and native numeric constraints.
  • name submits the amount and unitName submits the unit, defaulting to name followed by .unit.
  • Supply value and onValueChange when the application converts units or persists the result; unit selection alone keeps the supplied amount unchanged.
  • null represents a missing amount or unit. Unit option values must be unique and non-empty.

Not for

  • Assuming that choosing a different unit automatically converts the amount.
  • Relying on formatting to establish scientific precision or dimensional compatibility.

Three ways in. They share one source, so the pixels match whichever you pick.

1. Import the package

npm install @noorddev/vlak-react

// once, next to your app's root
import "@noorddev/vlak-react/css";

import { QuantityField } from "@noorddev/vlak-react";

Precompiled React and one stylesheet. No compiler to configure. Per-component imports work too: @noorddev/vlak-react/components/quantity-field.

2. Vendor the source

npx @noorddev/vlak-cli add quantity-field

The StyleX leaf lands in components/vlak/ with its dependencies, for your own compiler to own. See StyleX.

3. Through shadcn

npx shadcn add https://vlak.dev/r/quantity-field.json

The same registry item, installed by shadcn's CLI.

CSS only

<link rel="stylesheet" href="node_modules/@noorddev/vlak/css/vlak.css" />

No React. Link vlak.css and use the markup and classes below.

import { QuantityField } from "@noorddev/vlak-react";

<QuantityField label="Sample volume" name="volume" units={[{ value: "ul", label: "µL" }, { value: "ml", label: "mL" }]} defaultValue={{ amount: 250, unit: "ul" }} min={0} required description="Enter the amount and its unit" />

QuantityField

A native numeric input and unit selector. Selection never converts the amount.

PropTypeDefaultDescription
labelrequiredReactNode
unitsrequiredreadonly QuantityUnit[]
valueQuantityValue
defaultValueQuantityValue{ amount: null, unit: null }
onValueChange(value: QuantityValue) => voidRequests a quantity change. A unit change preserves the amount; the host owns conversion.
descriptionReactNode
unitNamestringname ? `${name}.unit` : undefinedInput names: name submits the amount; unitName defaults to name + '.unit'.
amountLabelstring"Amount"
unitLabelstring"Unit"
unitPlaceholderstring"Choose unit"
minnumber
maxnumber
stepnumber | "any""any"
requiredboolean
readOnlybooleanfalse

Also accepts Omit<FieldsetHTMLAttributes<HTMLFieldSetElement>, "defaultValue">.

KeysDoes
TabMoves between the amount input and unit selector.
Arrow keysUses native number stepping or opens and navigates the Vlak unit selector. Enter or Space confirms a unit; Escape closes its menu.
<fieldset class="rs-quantity-field"><legend class="rs-quantity-field-legend">Sample volume</legend><div class="rs-quantity-field-row"><label class="rs-quantity-field-label">Amount<input class="rs-input rs-input-full rs-quantity-field-control" name="volume" type="number" step="any" value="250" /></label><div class="rs-quantity-field-label"><span id="quantity-unit-label">Unit</span><div class="rs-select rs-select-fluid"><button type="button" class="rs-dropdown" role="combobox" aria-labelledby="quantity-unit-label" aria-expanded="false" aria-haspopup="listbox"><span>µL</span></button></div></div></div></fieldset>
.rs-quantity-field.rs-quantity-field-legend.rs-quantity-field-row.rs-quantity-field-label.rs-quantity-field-control.rs-quantity-field-description