---
title: "Reading level"
description: "The target we write to, how a readability score is calculated, and why the score is a diagnostic rather than the goal."
url: "https://opsinjs.pensievelabs.org/content/reading-level"
source: "https://opsinjs.pensievelabs.org/content/reading-level.md"
section: "Content & language"
kind: "content"
reviewed: "2026-09-20"
reviewer: "content"
aliases: ["readability score", "grade level", "plain language score"]
---

> Elements written as `<PascalCase … />` below are opsinjs documentation
> components. Their attributes are the content: the values they render are
> generated from `tokens/*.json` and `registry/catalogue.ts` and are
> published separately at https://opsinjs.pensievelabs.org/r/index.json and under the Reference
> section.
> Nothing is missing from this page. The data simply does not live in
> the prose.

<PageTemplate kind="content" />

## The rule [#the-rule]

**Write so that a reader who is not concentrating can follow it the first time.
Measure the result, then fix the sentences the measurement points at. Never fix
the score.**

Readability formulas count syllables, words per sentence and sometimes word
frequency. They are cheap, reproducible and extremely blunt. What they measure
correlates with comprehension; what they do not measure is whether the reader can
*use* the sentence, which is the thing health content is for.

Three properties of the formulas that matter in practice:

* **They cannot see meaning.** "Take two of the small white ones before food" and
  "Take two of the large blue ones after food" score identically. One of them may
  be dangerous.
* **They punish necessary words.** "Hydrochlorothiazide" and "appointment" both
  raise the score. One of them can be replaced and one cannot, and no formula
  knows which.
* **They can be gamed trivially.** Chopping every sentence at the comma lowers
  the score and raises the reading effort, because the reader now has to
  reassemble the relationship the comma expressed.

So a score is a **smoke alarm**: useful because it goes off, useless as a measure
of how well you cook.

### The target [#the-target]

We write to roughly the level of a UK national newspaper's news pages. The
common shorthand for this is "around age 9 to 11 reading level", and it is the
level public-sector health guidance in the UK generally aims at. Two
qualifications, both important:

* **It is a ceiling for the ordinary case, not a floor to hit.** Simpler is
  usually better; there is no prize for arriving exactly at the target.
* **It is suspended for safety-critical copy.** An `urgent` message is written for
  speed and unambiguity. If the clearest possible instruction scores badly,
  the instruction wins.

<ResearchNote evidence="opinion" date="2026-09-02">
  The reading-level target above is a widely-used convention in UK public-sector
  and health content practice rather than a finding we can cite to a specific
  study, and we state it as **our chosen convention**. We have not measured the
  reading level of this documentation or of any product built with opsinjs, and
  we publish no score. Any number you see attached to readability in this system
  will be generated by a named script or it will not exist.
</ResearchNote>

## Approved / Rejected [#approved--rejected]

<DoDont>
  <DoDont.Do>
    Take one tablet in the morning, with food. If you forget, take it as soon as you remember. Do not take it if it is nearly time for the next one.
  </DoDont.Do>

  <DoDont.Dont>
    Administration should occur once daily in the morning concomitantly with food; in the event of a missed dose, administration should occur upon recollection unless proximate to the subsequent scheduled dose.
  </DoDont.Dont>
</DoDont>

<DoDont>
  <DoDont.Do>
    Your reading was higher than usual, so take another one tomorrow morning.
  </DoDont.Do>

  <DoDont.Dont>
    Your reading was higher than usual. Take another one. Do it tomorrow. Do it in the morning.
  </DoDont.Dont>
</DoDont>

The second pair is the gaming failure. The rejected version scores better on
every formula and is harder to read, because four short sentences have destroyed
the causal link the reader needed.

<DoDont>
  <DoDont.Do>
    Call 999 now. Tell them you have chest pain.
  </DoDont.Do>

  <DoDont.Dont>
    If you are experiencing chest discomfort, it would be advisable to contact the emergency services.
  </DoDont.Dont>
</DoDont>

## Patterns [#patterns]

**Diagnosing a bad score.** The score tells you a page is hard; these five checks
tell you where.

<Steps>
  ### Find the longest sentence [#find-the-longest-sentence]

  Read it aloud. If you run out of breath, it has more than one idea in it. Split
  it at the idea boundary, not at the comma.

  ### Find the longest word that is not a clinical term [#find-the-longest-word-that-is-not-a-clinical-term]

  That word almost always has a shorter, commoner twin: "administer" is "take",
  "commence" is "start", "utilise" is "use", "prior to" is "before".

  ### Count the words before the main verb [#count-the-words-before-the-main-verb]

  Health copy tends to open with a subordinate clause. "If your readings have been
  higher than usual over the last few days, then…" is the shape to watch for.
  Move the main clause first.

  ### Look for the nominalisations [#look-for-the-nominalisations]

  "Make an application" is "apply". "Provide an indication" is "show". Turning
  verbs into nouns is the single largest source of unnecessary difficulty in
  institutional writing.

  ### Read the first sentence on its own [#read-the-first-sentence-on-its-own]

  If it does not contain the answer, no readability score will save the page.
</Steps>

**Sentence shapes that read easily**

> `Subject` `verb` `object`. `Consequence`.

> Your `measure` was `value`. That is `comparison`.

> If `condition`, `action`.

**When to break the target on purpose**

> Any `urgent` message · any dosing instruction · any legally required wording ·
> any sentence where the plainer version is ambiguous.

## Banned words [#banned-words]

The practices below are not banned outright. They are banned as *substitutes for
editing*.

| Banned practice                                   | Why                                                      | Do instead                     |
| ------------------------------------------------- | -------------------------------------------------------- | ------------------------------ |
| Reporting a readability score as a quality metric | It measures sentence and word length, not comprehension. | report what you changed        |
| Splitting sentences to lower a score              | Destroys the relationships between ideas.                | split at idea boundaries only  |
| Deleting a clinical term because it is long       | The reader needs to recognise it elsewhere.              | give the term and translate it |
| Setting a score as an acceptance criterion        | It becomes a target and stops being a measure.           | use it as a smoke alarm        |
| Publishing a score we have not generated          | It would be a measured number that is not measured.      | say there is no score yet      |
| Applying the target to `urgent` copy              | Clarity beats simplicity when somebody must act now.     | write for speed                |

## Related components [#related-components]

* **`ReadingLevel`** is the readout for a sample of copy. It is a P2 component
  and is not implemented; when it is, it reports the score *and* the longest
  sentence, because the second is the actionable half.
* **`Term`** is the sanctioned way to keep a long clinical word without paying
  its comprehension cost.
* **`CareCard`*&#x2A; and &#x2A;*`AlertBanner`** are the two surfaces where the target is
  most often suspended, and correctly so.
* **`ResultCard`** is the surface where the target matters most, because it is
  read under stress.

<Todo>
  Implement `<ReadingLevel>` and wire a readability pass into `pnpm run check` so
  that content pages report their longest sentence. No score should be published
  for this documentation until that script exists and has run.
</Todo>
