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.
| Banned | Because | Use instead |
|---|---|---|
| normal / abnormal | Describes 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 / unhealthy | A verdict on a life, from one number | "in the usual range" / "higher than the usual range" |
| good / bad | Moral framing of something largely outside the reader's control | Say the direction: "higher", "lower" |
| poor / failed | Failure language for a body | "lower than expected" |
| perfect / optimal | Sets up every future reading as a decline | "in the usual range" |
| positive / negative | Inverted in lay usage, where a "positive" result is usually the bad one | Name the finding: "X was found" / "X was not found" |
| elevated | Clinical register; means little to a lay reader | "higher than" |
Presentation rules
| # | Requirement | What must be visible on screen | Who owns it | Failure it prevents |
|---|---|---|---|---|
| 1 | The 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 range | An unowned band read as a threshold the product or opsinjs set for itself |
| 2 | The 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 screen | A status pill without a visible range asks the reader to trust an invisible rule |
| 3 | A 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 decision | A one-unit change flipping the whole surface from calm to alarming with nothing in between |
| 4 | Direction 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 string | Direction recoverable only by a reader who can see and interpret the dot's position |
| 5 | Nothing 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 cause | An observation read as a diagnosis the presentation layer is not entitled to make |
| 6 | Only 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 from | A status manufactured from a comparison that does not hold for this reader |
| 7 | The 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 visible | A 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.
Notifications and off-screen alerts
A push notification is a clinical statement delivered to a lock screen the product does not control, in front of people the reader did not choose.
Numbers, units and precision
The canonical rules for rendering a health number, covering digits, units, zero and rounding. Rounding is a truth claim here, not a formatting preference.