opsinjs
HealthNumbers on a screen

Unit systems

mmol/L against mg/dL, kilograms against stones and pounds, Celsius against Fahrenheit. Conversion is where a wrong answer is a plausible number, not an error.

What this means

A unit system is a correctness constraint rather than a presentation one, and what distinguishes it is that a unit failure is invisible to the reader. A missing translation shows a raw key and a wrong date format looks wrong, so both defects are caught by anyone who looks at the screen. A unit failure produces a number that is well formed and plausible in the system it was computed for, and wrong for the reader in front of it.

Blood glucose is reported in two systems. Much of the world reports it in mmol/L, where everyday values are single digits with one decimal, and the United States reports the same measurement in mg/dL, where everyday values are in the tens and hundreds. A reader who has learnt one scale and is shown the other without a label has no cue that separates a change of unit from a change in their body, because the only thing that has visibly changed is the number.

Body weight fails through notation rather than through scale, because the same digits carry two readings inside one system. A reader who thinks in stones and pounds and is shown 11.3 will read it as eleven stone three pounds. The value is eleven point three stone, which is eleven stone four, so the figure displayed and the figure read differ by one pound. That discrepancy is small against a weight trend and decisive wherever weight is an input to a calculation, such as a paediatric dose, which this page excludes under "What this does not cover".

Temperature differs from the other two because a reader recognises the plausible range of a body temperature in either scale, so a reading in the wrong scale is visible as a wrong reading. The residual risk sits in the threshold rather than in the reading, because a fever threshold expressed in the wrong scale is a wrong threshold.

The rule

The unit system is a user preference, stored, respected everywhere, and never inferred silently. A converted value is labelled as converted, and conversion happens once, at the display boundary.

The ten rules

#RequirementWhere it appliesWho owns itFailure it prevents
1One canonical unit per metric is used in storage and in every API, and conversion is a rendering concern that never round trips through storage.Storage and APIThe product's data modelA stored figure whose unit depends on the preference in force when it was written
2The unit preference is explicit, and it is held per metric family wherever readers genuinely differ between families, such as kilograms for weight alongside feet and inches for height.Settings and storageThe readerA single global switch that forces one system onto every metric
3Locale supplies the initial default and never the settled answer, because readers move between countries, clinicians and patients differ, and a device may report in a system its owner does not use.Onboarding and defaultsThe reader, asked onceA default that is wrong for the whole relationship and is never corrected
4A value shown in a system other than the one it arrived in is labelled as converted, in the form "Converted from 98 mg/dL."DisplayValueA converted figure read as the figure the device reported
5Ranges, thresholds and statuses convert with the value they are compared against, and the comparison itself runs on canonical units only.The display boundaryThe clinical source owns the thresholdA status derived from a value and a range held in different units
6Rounding happens after conversion and uses the destination metric's precision, and an original value is never re-derived from a rounded conversion, because the round trip is lossy. See Numbers, units and precision.DisplayThe destination metricA value that drifts each time the reader switches systems
7The unit is part of the entry field, visible at all times, switchable in place and remembered for the next entry. See Units and numeric entry.EntryReadingInputA figure typed in one system and stored as another
8Compound imperial quantities are entered compound, so stones and pounds is two inputs and feet and inches is two inputs.EntryReadingInputA compound quantity collapsed into one decimal field, which the reader then has to compose by hand
9Entry is plausibility-checked against the entered unit, and a figure far from the reader's own previous readings raises a question rather than a rejection: "That is much higher than your usual readings. Is it in mg/dL?"EntryThe reader confirms or correctsA mg/dL figure stored as mmol/L
10Exports, shares and print carry the unit unambiguously, because the recipient may not share the reader's preference. See Sharing with a clinician.Export, share and printA recipient reading the figure in their own default system

Units that need explicit handling

The measurements below are the ones a consumer health product has to handle explicitly.

MeasurementCommon systemsThe specific hazard
Blood glucosemmol/L · mg/dLBoth plausible; ranges do not overlap but neither looks wrong
Cholesterolmmol/L · mg/dLAs above, with more sub-measures to get wrong
Body weightkg · lb · st + lbDecimal stone misread as stone-and-pounds
Heightcm · ft + inCompound entry; decimal feet is meaningless to most readers
Temperature°C · °FFever thresholds are scale-specific
Blood pressuremmHg (universal)Rarely converted, frequently mis-composed
Distancekm · milesConversion error is visible to the reader, so the risk is inconsistency between screens rather than a misread value
Energykcal · kJFactor of about four; both called "calories" colloquially

Why (evidence)

Applying it

Do

Render "5.4 mmol/L" with a visible, tappable unit control, and carry the reader's choice across the whole product.

Don’t

Render "5.4" with the unit in a legend at the bottom of the screen, or only in the chart axis. A unit held there is absent from the value's accessible name, so a screen reader announces the figure without it.

Do

Take "11 st 4 lb" as two labelled inputs, store it as kilograms, and display it back in the form it was entered.

Don’t

Offer "11.3 st" in a single decimal field. A decimal stone field is read as stones and pounds by readers who think in that system, so a figure meant as eleven stone three pounds is stored as eleven point three stone, which is eleven stone four, and the record is one pound out.

Do

State the provenance and the conversion together: "This reading came from your meter in mg/dL. Shown here as 5.4 mmol/L."

Don’t

Convert on import and store the converted value. The original is now unrecoverable, and every later precision decision inherits the rounding.

Do

Default from locale, then ask once in onboarding: "Which units do you use for weight?"

Don’t

Infer the system from the device region and never ask. A UK phone does not indicate a kilogram reader, and a preference set by inference is never corrected, because nothing on screen tells the reader that a choice was made on their behalf.

Components that implement this

Value and ReadingInput are specified as the only two places at which a unit system is resolved, one for display and one for entry. Every other component passes canonical values, which is what makes rule 5 a structural property of the system rather than a rule each developer has to remember.

What this does not cover

  • Conversion factors and clinical correctness. opsinjs ships no factors and no thresholds. The factor is determined by the analyte and is owned by the clinical source a product works from.
  • Translation of the surrounding language is covered by Internationalisation.
  • Number formatting itself is canonical at Numbers, units and precision.
  • Dose calculation of any kind. If your product calculates a dose, unit handling is a safety-critical function and this page is not sufficient.
  • Non-SI clinical units are those that are neither metric nor imperial, such as international units and unit systems specific to a single assay. Handle them as their own metric with a fixed unit.

Updates to this page

Last read through against the system on 2026-09-02. Due for review every 12 months; expiry is reported by pnpm run check:freshness.

On this page