Quantity field

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

Sample volume

Change the unit to express the same entered 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