opsinjs
HealthNumbers on a screen

Reference ranges

How to show a value against a range without implying a diagnosis, and why the word "normal" is banned from every user-facing string about a person's own result.

What this means

A reference range is a statistical statement about a population, usually constructed so that a defined majority of an apparently healthy reference group falls inside it. It is produced by a specific laboratory, using a specific assay, for a specific population, and it varies between laboratories for the same test.

That definition supports neither of two conclusions a reader may draw from it. It does not say that a value inside the range is healthy. It does not say that a value outside it is disease. By construction, a proportion of perfectly well people fall outside (that is what "a defined majority" means), and a person can be seriously unwell with every value comfortably inside.

A conventional range visualisation prints the range as a bar, the value as a dot, and labels the middle "Normal". A band labelled "Normal" is reasonably read as a statement about the person rather than about the measurement, and the negation of that statement has no gentler form in English: a reader whose value sits outside the band has been told they are not normal, and no statistical caveat placed beside the bar survives contact with the word.

The misreading is produced by the wording and the layout rather than by the measurement or by the range behind it. Wording and layout are the presentation layer's responsibility, which places this failure inside opsinjs's scope rather than the issuing laboratory's.

The rule

Show the value, show the range it is being compared against, name whose range it is, and never characterise the person.

Banned words in user-facing strings

Each word below is banned from any user-facing string about a person's own result, and the Use instead column is the replacement wording this system specifies.

BannedBecauseUse instead
normal / abnormalDescribes the person, not the measurement; its clinical sense and its lay sense are different words spelled the same way"in the usual range" / "outside the usual range"
healthy / unhealthyA verdict on a life, from one number"in the usual range" / "higher than the usual range"
good / badMoral framing of something largely outside the reader's controlSay the direction: "higher", "lower"
poor / failedFailure language for a body"lower than expected"
perfect / optimalSets up every future reading as a decline"in the usual range"
positive / negativeInverted in lay usage, where a "positive" result is usually the bad oneName the finding: "X was found" / "X was not found"
elevatedClinical register; means little to a lay reader"higher than"

Presentation rules

#RequirementWhat must be visible on screenWho owns itFailure it prevents
1The range is always attributed. The surface names whose range it is at the point where the comparison is made."Your laboratory's usual range", or "the range this device uses", next to the band itself.The laboratory, the device manufacturer or the clinical team that issued the rangeAn unowned band read as a threshold the product or opsinjs set for itself
2The range is shown rather than merely applied.The endpoints of the range, beside the value being compared with them.The supplier of the range owns the endpoints; the implementing team owns whether they reach the screenA status pill without a visible range asks the reader to trust an invisible rule
3A small change near the boundary produces a small change on screen. A value just outside a range is presentationally close to one just inside.The distance between the value and the boundary, so that "just outside" and "far outside" can be told apart.The implementing team, because the treatment either side of the boundary is a presentation decisionA one-unit change flipping the whole surface from calm to alarming with nothing in between
4Direction is stated in words.The direction in words, for example "higher than the usual range", and not only the position of a dot along a bar.The implementing team, writing the stringDirection recoverable only by a reader who can see and interpret the dot's position
5Nothing on the surface asserts a cause.The observation only: "Higher than the usual range" is an observation and "You may be dehydrated" is a diagnosis.The reader's clinician; no surface in the product attributes a causeAn observation read as a diagnosis the presentation layer is not entitled to make
6Only a range built for the reader's population is shown. A range derived from an adult population is not shown to a reader who is fifteen.No range at all, where none of the available ranges covers the reader.The supplier of the range, who also defines the population it was constructed fromA status manufactured from a comparison that does not hold for this reader
7The reader can always see the raw value.The value itself, with its unit, alongside any gauge, bar or dial drawn around it.The laboratory or device that produced the measurement owns the value; the implementing team owns keeping it visibleA gauge standing in for a number the reader can no longer recover

"Why (evidence)" below classifies rule 3 as opinion and does not classify the other six.

Heart. Illustrative only

148 units

Your range: 90 to 130 units

Needs attention. Contact your care team about this reading. It is outside the range they set for you.

The thresholds in this demo are arbitrary and exist only to move the specimen. opsinjs does not own clinical thresholds: they come from the service, a guideline, or the reader’s own clinician, and a design system that shipped defaults for them would be making clinical decisions for every product that installed it.

The values in any range demonstration in these docs are placeholders chosen to show formatting. They are not reference ranges and must not be copied into a product.

Why (evidence)

Applying it

Do

"5.4 mmol/L. In your laboratory's usual range (3.9 to 5.6 mmol/L)." The string carries the value, the comparison, the owner of the range and the range's endpoints.

Don’t

"5.4 Normal ✓". The tick and the word together assert a verdict on the person, and the surface shows neither the range nor whose range it is.

Do

"Slightly above your laboratory's usual range. This often needs no action on its own. Your clinician will look at it alongside your other results." The string states the direction, attributes the range and names who will interpret it.

Don’t

"ABNORMAL out of range." The string applies a clinical adjective to the reader in capitals, gives no indication of how far outside the range the value sits, and reaches someone who cannot ask a follow-up question until Monday.

Do

Render the range as a labelled band with its endpoints visible, and put the value inside it. A reader can then judge "just outside" versus "far outside" for themselves.

Don’t

Render a red-to-green gradient with no numbers. A gradient asserts a continuous quality scale that reference ranges do not have, and it carries nothing at all in greyscale.

Do

Where sex-, age- or pregnancy-specific ranges exist, use the one that applies and say which: "usual range for adults over 18".

Don’t

Apply one adult range to everyone because it is the one in the config file. A range built for a population the reader is not in manufactures a status from a comparison that does not hold.

Components that implement this

RangeBar is specified to require an attributed range, so a bare pair of numbers with no owner is a validation error rather than a rendered bar. The banned-word list above is expressible as a lint rule over user-facing strings, and until such a rule exists the check falls to review.

What this does not cover

  • The ranges themselves. opsinjs ships no reference ranges for any metric. They are supplied by the laboratory, the device manufacturer or the clinical team behind the product, and each one arrives with an owner.
  • Deciding a status from a range. Being outside a range is not automatically attention; see Clinical status semantics.
  • Number formatting. The canonical treatment is at Numbers, units and precision.
  • Risk expressed as a probability. Risk stated as a probability rather than as a range is covered at Risk and statistics.
  • Composite scores. A score with no reference interval at all has band names invented by the product, and those names must be disclosed as such.
  • The wider vocabulary. Full plain-English replacements live at Plain-English A to Z.

Updates to this page

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

On this page