---
title: "FAQ"
description: "Twenty questions that would otherwise become issues, each answered at its own anchor."
url: "https://opsinjs.pensievelabs.org/start/faq"
source: "https://opsinjs.pensievelabs.org/start/faq.md"
section: "Start here"
kind: "guide"
reviewed: "2026-09-20"
reviewer: "content"
aliases: ["faq", "frequently asked questions", "common questions"]
---

> 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="guide" />

## Overview [#overview]

Every answer here is short, opinionated and linked to the page that argues the
case properly. Each question has its own anchor, so you can send someone a link to
the answer rather than to the page.

Something that did not work is a *failure* rather than a question, and
[Troubleshooting](./troubleshooting.mdx) is the other page for it.

## About the project [#about-the-project]

### What is opsinjs, in one sentence? [#what-is-opsinjs-in-one-sentence]

A React design system for consumer health apps: the components that show a person
their own numbers, and the rules that keep those numbers honest. The rules are the
larger half. [Introduction](../index.mdx).

### Can I use it today? [#can-i-use-it-today]

In a prototype, yes. Every catalogue row is implemented and installable, and
their registry items carry the whole of their source. Two things decide whether
that is any use to you yet. There is no npm package and there never will be one,
because opsinjs is copied in as source through the shadcn CLI. And
`opsinjs.pensievelabs.org`, the canonical host, is not serving, so `@opsinjs`
resolves only against a registry you point it at yourself. A `shipped` API may
change in any release. Every component has been audited against WCAG 2.2 AA, but
that audit was run by the people who wrote the component rather than an
independent reviewer, and no component has had a clinical review, so none of it
belongs in front of a patient yet.
[Release phases](../project/release-phases.mdx) defines what each status promises,
and [ADR 0025](../project/decisions/0025-the-audit-is-author-run.mdx) records
what the audit did and did not cover.

### Is it free, and can I use the guidance without the code? [#is-it-free-and-can-i-use-the-guidance-without-the-code]

Yes to both, and they are licensed separately: the code under an open-source
software licence, the written guidance under a documentation licence that allows
reuse with attribution. The doctrine is useful against any stack, and we would
rather it were reused than reinvented.
[Licence and attribution](../project/licence-and-attribution.mdx).

### Why another design system? [#why-another-design-system]

Because general-purpose systems answer "how do I render a badge" and health
products need an answer to "what is this badge allowed to assert about someone's
body". Nothing in a general-purpose system stops you colouring a category by
severity, printing a bare percentage change, or writing the word *normal* next
to a result. All three are ordinary, avoidable harms.
[Is opsinjs right for this project?](./is-opsinjs-right.mdx).

## Using it [#using-it]

### Is it a component library or a registry? [#is-it-a-component-library-or-a-registry]

A registry. Components are copied into your repository as source through the
shadcn CLI, so you own and can change every line. You are not installing a
dependency you cannot see inside.
[Registry](../registry/index.mdx), and the reasoning is in
[ADR 0002](../project/decisions/0002-shadcn-registry-distribution.mdx).

### Do I have to adopt all of it? [#do-i-have-to-adopt-all-of-it]

No. Take one component, or take only the tokens, or take only the doctrine and
none of the code. The one thing that does not work is taking a component and
discarding the rule that governs it. A `StatusPill` used as a decorative badge
is a misuse. Nothing stops you mechanically: the
[lint plugins](../handbook/tooling/index.mdx) that would catch it are specified
and not built, so this one is on your code review.

### Does it work alongside shadcn/ui components I already have? [#does-it-work-alongside-shadcnui-components-i-already-have]

That is the intended arrangement. opsinjs is a shadcn-spec registry and shares the
`components.json` conventions, so it composes with a namespaced install rather
than replacing what you have. Two caveats: opsinjs is built on Base UI rather than
Radix, so you may end up with two primitive libraries in the tree; and opsinjs's
token layer is additive but its CSS position matters.
[components.json](./installation/components-json.mdx).

### Why Base UI rather than Radix? [#why-base-ui-rather-than-radix]

Mainly the exit-animation contract: Base UI's state attributes make "animate out
before unmounting" a declarative CSS concern rather than a JavaScript one, which
matters for a system where every animation must also have a documented
reduced-motion form. Choosing one primitive library across docs chrome and product
also keeps a single behaviour vocabulary.
[ADR 0001](../project/decisions/0001-base-ui-not-radix.mdx).

### What happens when you change a component I have already copied? [#what-happens-when-you-change-a-component-i-have-already-copied]

You take the change deliberately, with a diff, or you never take it. Copied source
means no silent updates and no upgrade you did not ask for; the cost is that
improvements do not arrive on their own. Diff the registry item against the copy
in your tree to see what has moved.
[Upgrading](./installation/upgrading.mdx).

### Do I need a React framework, or will plain React do? [#do-i-need-a-react-framework-or-will-plain-react-do]

Plain React with Vite is fine. What you cannot do without is React 19, Tailwind
v4, and control over stylesheet order.
[Framework support](./framework-support.mdx).

## Health, safety and scope [#health-safety-and-scope]

### Is opsinjs a medical device? [#is-opsinjs-a-medical-device]

No, and adopting it does not change your product's regulatory status in either
direction. It has not been submitted to or reviewed by any regulator, and no
conformity assessment has been performed on it. If your product would be a medical
device without opsinjs, it still is with it.
[Safety, scope and limitations](./safety-scope-and-limitations.mdx).

### Will a component tell me whether a value is dangerous? [#will-a-component-tell-me-whether-a-value-is-dangerous]

Never. Status is an input to a component, never a computation inside one, and
there is no `threshold` prop. The mapping from a number to a clinical level
belongs in one auditable place in your product, approved by whoever is accountable
for clinical decisions. This is the system's most consequential constraint and it
is not configurable.

### Why is the word "normal" banned? [#why-is-the-word-normal-banned]

Because it means something specific and statistical to a clinician and something
reassuring and absolute to everyone else, and health products are read by everyone
else. A result inside a reference range is not a guarantee of health, and printing
*normal* next to it invites a reader to conclude that it is.
[Reference ranges](../health/reference-ranges.mdx) covers what to write instead.

### Can I use it for a clinician-facing product? [#can-i-use-it-for-a-clinician-facing-product]

You can, and you should not. Clinical workstations need density, abbreviation and
raw values; every default here goes the other way, and you would spend your time
fighting the system rather than using it.
[Is opsinjs right for this project?](./is-opsinjs-right.mdx).

### Does opsinjs handle units such as millimoles versus milligrams per decilitre? [#does-opsinjs-handle-units-such-as-millimoles-versus-milligrams-per-decilitre]

It treats units as a correctness problem rather than a localisation one, which
means the formatting contract and the conversion rules are documented and testable
rather than left to a locale file. It does not perform your conversions or decide
which system a given reader should see.
[Unit systems](../health/unit-systems.mdx).

## Design and theming [#design-and-theming]

### Can I use my own brand colours? [#can-i-use-my-own-brand-colours]

Yes, through the theme generator, which derives a full gamut-aware,
contrast-validated system from one brand colour. It tells you when your brand
colour cannot carry the meaning you want it to. What you cannot do is give a
brand colour to the clinical status axis.
[Theme generator](../theming/theme-generator.mdx).

### Why can't a category colour signal that something is bad? [#why-cant-a-category-colour-signal-that-something-is-bad]

Because the reader cannot tell which question a colour is answering unless the two
questions use different channels. If Sleep is blue and a bad night turns it amber,
then amber sometimes means "sleep" and sometimes means "pay attention", and every
subsequent colour judgement on the screen is ambiguous.
[The two colour axes](../health/two-colour-axes.mdx).

### Why does this documentation site look different from the components it documents? [#why-does-this-documentation-site-look-different-from-the-components-it-documents]

Deliberately. The docs chrome is dense and square because it is a reference tool
for professionals; the product theme is squircle, system-typeface and generous
because it is read by an anxious person on a phone. Making the documentation look
like the product would misrepresent both.
[Lyra and the docs chrome](../theming/lyra-and-the-docs-chrome.mdx).

### Is there a Figma library? [#is-there-a-figma-library]

Not yet. The token source exists and the W3C DTCG export that maps onto Figma
Variables is specified, but there is no published file, kit or plugin.
[Design handoff](../theming/design-handoff.mdx).

## Agents and machines [#agents-and-machines]

### How do I get these docs into an AI tool? [#how-do-i-get-these-docs-into-an-ai-tool]

Three ways, all first-class: append `.md` to any documentation URL for processed
markdown; fetch `llms.txt` or one of its per-pillar shards; or point a shadcn MCP
client at the registry. [Agents](../agents/index.mdx).

### Why does a page exist for a component that is not built? [#why-does-a-page-exist-for-a-component-that-is-not-built]

Because the alternative is a 404, and a 404 is the input from which an agent
invents an API. A page that exists, says `planned`, and carries a
machine-readable not-implemented marker at a guessable URL is a definitive
negative answer. No component sits at `planned` today, so the mechanism is
currently idle, and it is the thing that keeps the first specification written
after this sentence from being read as code. That is the single most important
thing this site does for a machine reader.
[Reading these docs](./reading-these-docs.mdx#for-agents).

## Contributing and governance [#contributing-and-governance]

### How do I propose a component, or argue with a specification? [#how-do-i-propose-a-component-or-argue-with-a-specification]

A proposal is a document answering eight questions, not a pull request, and
arguing with an existing specification is usually more valuable than writing a
new one. [Proposing a
component](../handbook/contributing/proposing-a-component.mdx) has the questions
and the four reasons a proposal is normally declined;
[Community](../project/community.mdx) says where to take it.

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

An answer here is only useful if it is current. Two ways to check:

1. **Look at the review date in the page header.** This page is reviewed every six
   months, and an expired review is reported in CI rather than hidden.
2. **Check [State of the system](../project/state-of-the-system.mdx)** if the
   answer concerns what does or does not exist. It is the dated, blunt account
   and it is more current than the
   [changelog](../project/changelog/index.mdx), which has no entry yet for the
   components that now exist. This page is a summary of both.

## Troubleshooting [#troubleshooting]

**Your question is not here.** Search first. Every page carries the words a
reader would actually type as `aliases`, including clinical vocabulary. If the
search returns nothing, that is recorded, and repeated zero-result searches are
how this page grows.

**The answer here contradicts a component page.** The component page wins. This
page is a summary; the specification is the contract.

**You have a question that is really a bug report.** Open a docs issue and name
the page path in it. [Community](../project/community.mdx) says where to file
it.

## Next [#next]

* [Troubleshooting](./troubleshooting.mdx) is for questions that are really
  failures.
* [Is opsinjs right for this project?](./is-opsinjs-right.mdx) helps if you are
  still deciding.
* [Community](../project/community.mdx) is where to ask something this page does
  not answer.
