---
title: "Recipes"
description: "Task-first builds gather the components, tokens, copy and safety checks for one job into one scroll."
url: "https://opsinjs.pensievelabs.org/recipes"
source: "https://opsinjs.pensievelabs.org/recipes.md"
section: "Recipes"
kind: "guide"
reviewed: "2026-09-20"
reviewer: "engineering"
---

> 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.
> `<StubNotice>` IS THE EXCEPTION, AND IT IS THE ONE TO READ. It is a
> paired element rather than a self-closing one, and the text between
> its opening and closing tags is prose an author wrote, reproduced
> below word for word. That prose is where this page says whether the
> component has been reviewed. Read the children, not only the
> attributes.

<PageTemplate kind="guide" />

## Overview [#overview]

A component reference answers "what is this thing?". A recipe answers the
question people actually arrive with: &#x2A;*"I have a blood pressure reading and a
reference range. What do I put on the screen?"** Every surveyed design system
documents the first question well and the second one barely at all, which is why
the same three mistakes keep being shipped: a value with no unit, a range with
the word *normal* in it, and a red banner used for something that is not urgent.

A recipe is one task. It names the components and tokens involved, the order to
assemble them in, the words that go on the screen, and the safety and
accessibility checks that specific task can fail. It ends where the task ends.
That is not the last instruction, but the point where you can tell for yourself
whether you got it right.

Recipes sit in the middle of a three-layer split that the whole site follows:

* **[Foundations](../foundations/index.mdx)** says what a token *means*.
* **[Handbook](../handbook/index.mdx)*&#x2A; and &#x2A;*[Theming](../theming/index.mdx)**
  show how you *change* it.
* **Recipes** say what to *assemble&#x2A; for one job.
  &#x2A;*[Patterns](../patterns/index.mdx)*&#x2A; are the same job at flow scale;
  &#x2A;*[Screens](../screens/index.mdx)** are the whole surface.

If you are choosing between a recipe and a pattern: a recipe fits in one scroll
and produces one composed thing. A pattern spans several screens and describes a
sequence of decisions.

<Callout title="The parts install; the recipes are still specifications">
  Every component a recipe names is `shipped`. They are installable, and
  free to change their API in any release, and none of them has been reviewed.
  Each recipe's **What you need** table
  carries the current status of every part, and that table is the thing to trust; no
  recipe restates a count in prose. What a recipe itself contains is a **specification of
  the build**, not a transcript of one: it tells you what to assemble and why, and
  it deliberately holds no code you could paste, because a recipe that names the
  wrong component or approves the wrong sentence would be wrong whether or not the
  code beneath it existed.
</Callout>

## What a recipe contains [#what-a-recipe-contains]

Every recipe has the same seven sections, in the same order, so you can skim to
the one you need.

| Section       | What it is for                                                                                                              |
| ------------- | --------------------------------------------------------------------------------------------------------------------------- |
| The task      | The goal in the reader's terms, and the situation that produces it. If your situation is not this one, stop here.           |
| What you need | The components and tokens involved, each with its status, so you can see immediately how much of this is real.              |
| Build it      | The ordered steps, each with the reasoning that lets you adapt it rather than copy it.                                      |
| The copy      | The words on the screen and the rule each one follows. Health UI fails in its sentences at least as often as in its markup. |
| Get it right  | The safety and accessibility checks *this task* can fail, phrased so you can run them.                                      |
| Variations    | The near-miss versions of the task and how each changes the steps.                                                          |
| Related       | Where to go next, with the reason to go there.                                                                              |

Two conventions are worth knowing before you read one:

**A recipe carries no status of its own.** Only a component page does. However
finished the writing is, and however much of the component roster is now
installable, no recipe has been assembled and reviewed end to end as a working
example, and each says so in its own `<Todo>` or `<StubNotice>`. The per-part
statuses in **What you need** are the ones that tell you what will compile.

**Recipes name components; they never define behaviour.** If a recipe seems to
be inventing a rule, it is quoting one. The rule lives in
[Health](../health/index.mdx) or [Content & language](../content/index.mdx) and
the recipe links to it. Where the two disagree, the doctrine page wins and the
recipe is a bug.

## The recipes [#the-recipes]

Start with &#x2A;*[Choose a component](./choose-a-component.mdx)** if you are not sure
what you are building yet. It is the only recipe whose output is a decision
rather than a surface, and every other recipe assumes you have already made it.

The remaining six are ordered from the most common job to the least:

1. **[Build a health metric card](./health-metric-card.mdx)** puts one number on
   a dashboard, with its unit, its age and its category.
2. **[Show a value against a reference range](./value-against-a-range.mdx)** is
   the highest-stakes display in the system, and the one with the most ways to
   imply a diagnosis by accident.
3. **[Capture a daily log entry](./daily-log-entry.mdx)** covers repeated
   one-handed entry, where friction decides whether the data exists at all.
4. **[Show a trend with an honest caption](./trend-with-a-caption.mdx)**
   separates the direction of a change from whether it is good news.
5. **[Escalate an alert without alarming](./staged-alert.mdx)** covers the
   escalation ladder and the per-screen budget that stops it collapsing into
   noise.
6. **[Ask for consent before collecting](./consent-before-collection.mdx)**
   keeps consent granular, revocable and recorded, asked at the moment of value.

## Recipes we have not written yet [#recipes-we-have-not-written-yet]

These are known gaps, listed here rather than left to be discovered. Each is a
real task that a health product has to solve and that no recipe currently covers
end to end.

<Todo>
  **Disclose a result somebody may not want to see.** The moment between tapping a
  notification and reading an out-of-range result. Covered as a flow in
  [Result disclosure](../patterns/result-disclosure.mdx); not yet as a build.
</Todo>

<Todo>
  **Explain a number in plain English.** Turning a measured value into a sentence a
  reader without numeracy confidence can act on. The vocabulary exists in
  [Plain-English A to Z](../content/plain-english-a-z.mdx) and the formatting
  rules in [Numbers, units & precision](../health/numbers-units-precision.mdx);
  the assembly step between them is unwritten.
</Todo>

<Todo>
  **Show data you cannot vouch for.** Stale, partial and estimated values on a
  screen that also carries fresh ones. The states are defined in
  [Data states](../foundations/data-states.mdx) and the doctrine in
  [Uncertainty & staleness](../health/uncertainty-and-staleness.mdx); the recipe
  that composes them is missing.
</Todo>

<Todo>
  **A today screen.** The dashboard that most consumer health apps open on. The
  five [Screens](../screens/index.mdx) specimens do not include one, which is the
  largest single gap in the specimen set.
</Todo>

## Verify it worked [#verify-it-worked]

You have read a recipe correctly if you can answer these three questions about
what you just built, without looking anything up:

1. **Which axis is each colour on?** Every coloured element on the screen is
   either identifying a category or grading a clinical status, never both. If you
   cannot say which, read [The two colour axes](../health/two-colour-axes.mdx)
   before you ship.
2. **What does the screen say if the colour is gone?** Turn the screen grey. The
   status must still be legible from the word and the icon. This is the single
   check that catches the most defects.
3. **Who assigned the status?** Not the component, and not the recipe. A clinical
   rule owned by your product assigned it, and you can name where that rule
   lives. If the answer is "the UI decided", you have shipped an unlicensed
   clinical judgement.

## Troubleshooting [#troubleshooting]

**"The recipe uses a component that does not exist."** Check its chip in **What
you need**. A `shipped` chip means the code is there and the install command on
the component's own page will fetch it. No recipe shows a `planned` chip today.
Were one to appear it would mean a specification with nothing behind it yet, and
you would reach for a deliberate substitute rather than invent an API that
happens to share the name.

**"The recipe and a component page disagree."** The component page wins on the
component's own API and anatomy; the doctrine page wins on the rule. Recipes are
the layer most likely to drift, so please
[report it](../project/index.mdx) rather than picking one.

**"My data does not match any recipe."** Read
[Choose a component](./choose-a-component.mdx). It covers several shapes that
have no recipe yet, and names the shapes that have no component either.

**"I need to change a token to make this work."** Then the recipe is probably
wrong for your case, or the token is. Recipes never instruct you to override a
token; if you need to, [Theming](../theming/index.mdx) is the place, and
[Adding your own tokens](../theming/adding-your-own-tokens.mdx) is the way that
survives an upgrade.

## Next [#next]

* **[Choose a component](./choose-a-component.mdx)** is the decision table, if
  you do not know what you are building yet.
* **[Screens](../screens/index.mdx)** covers the same components composed into
  whole surfaces, which is where a correct component and a wrong page order
  still produce an unusable result.
* **[Safety review checklist](../health/safety-review-checklist.mdx)** is the
  pre-ship pass for anything that puts a health value on a screen.
