Start

The component registry

Twenty-nine installable items, shadcn-compatible. What is interesting about them is not what they render — it is what their APIs refuse to express, because a rule in a document is advice and a rule in a type signature is a rule.

Stable · v1.0 React 19 · TypeScript No runtime dependencies
What this is, and what it is not

A reference implementation of the rules, not a validated library. These components typecheck under strict and are render-tested in Node against 57 published rules. Nothing here has been opened in a browser, used on a touch device, exercised with a screen reader, or run in a real application. See Status & limitations.

Installing

Install foundations first. It carries the token contract — including the IEC 60601-1-8 alarm extension and its parity requirement — plus njt-tokens.json, which states which tokens are governed and why in a file your build can read, rather than only as prose on a site your team may never visit.

$ npx shadcn@latest add https://md.notjustany.tech/r/foundations.json
$ npx shadcn@latest add https://md.notjustany.tech/r/alert-banner.json

The index at /r/registry.json lists every item. Each component page ends with the command for that component, and check-registry.mjs fails the build if any published command points at something that is not built — a rule that exists because all twenty-nine of them returned 404 for months.

Dependencies

None at runtime. Not clsx, not tailwind-merge, not Radix. A design system for regulated software should not oblige its consumer to justify a dependency tree in a technical file, so the class joiner is six lines and ships inside foundations. Swap in your own cn if you already have one.

The components are unstyled beyond the token contract and reference the design tokens throughout, so they inherit whatever theme the tokens define.

The catalogue

Generated from registry/registry.json, so it cannot drift from what is actually published.

ItemWhat it is What its API refuses
Foundations — tokens & primitives
foundations
The token contract, including the IEC 60601-1-8 alarm extension, plus the shared types every other item depends on. Install this first. Alarm tokens identical in both themes by contract, shipped with the reason they may not change.
Alert banner
alert-banner
IEC 60601-1-8 priority-coded alarm banner. No bulk acknowledgement, no dismiss for an alarm condition. No onAcknowledgeAll, no array form, no dismiss for an alarm condition.
Status chip
status-chip
The state of one object the reader is already looking at. No icon-only form.
Badge
badge
An exact count of things elsewhere. No capping, so “99+” cannot be produced. No max prop, so 99+ cannot be produced.
Pagination
pagination
A list with its denominator always stated. total is required and exact — there is no unknown-total mode.
Key–value pair
key-value
A measurement, or a typed absence. Not-measured cannot arrive here as a blank. A discriminated union, not string | null: not-measured cannot arrive as a blank.
Empty state
empty-state
Proves the system looked, rather than showing nothing. searched is required — the proof that it looked.
Progress
progress
A determinate bar. Was one item with Activity, Skeleton and PendingValue — four answers to “not here yet” under one command. value, max and unit are all required, and there is no shape that could discard them.
Activity
activity
The indeterminate indicator, linear, circular or inline. No value on the type at all — it cannot claim to know how long.
Skeleton & pending value
skeleton
Placeholders that reserve the shape of what is coming. Skeleton has no value variant; a grey bar never stands in for a number.
Numeric input
numeric-input
Spin box with a clinical envelope. Empty is distinct from zero; out-of-range is refused, not warned. number | null that never coerces — an unset rate is not a rate of zero.
Text field
text-field
Labelled input with a remedy-bearing error. No placeholder-as-label. placeholder is omitted from the prop type.
Textarea
textarea
Multi-line input that never silently truncates what a clinician typed. No maxLength attribute, so keystrokes are never silently swallowed.
Checkbox
checkbox
Stages a change rather than applying one. indeterminate reaches the element, not just the styling.
Radio
radio
Nothing selected by default. A pre-selected radio is an answer nobody gave.
Switch
switch
Takes effect the moment it moves. effect has one permitted value, so a switch that defers cannot be declared.
Select
select
A native select, with an explicit unselected state. placeholderOption for anything with no safe default.
Search
search
Patient search where the identifier carries equal weight to the name. Identifier and date of birth carry the same weight as the name.
Card
card
Surface container, plus the interactive form as a real link. The interactive form is a real link, not a div with a handler.
Dialog
dialog
Blocking, and only with a real branch. Confirmation is disarmed on appearance. Both confirm and cancel are required; confirm is disarmed for 400 ms.
Toast & notification queue
toast-queue
Transient messages. Alarm conditions are unexpressible by construction. The tone union omits critical and urgent.
Data grid
data-grid
A real table with scoped headers, units in the header and tabular figures. A real table with scoped headers; empty is required.
List
list
Flat lists with a selection header. The header states what a bulk action would act on — never a bare “Select all”.
Tree
tree
Nesting, with its own expansion state and traversal. Not a variant of a list; a flat worklist has no use for one.
Tabs
tabs
Roving-tabindex tab list with counts, so a hidden panel can be skipped safely. Counts on tabs, so a hidden panel can be skipped safely.
Accordion & panel
accordion
Collapsing with a required summary. Panel is the default. summary is required on every collapsed item.
Filter
filter
Filters that state what they are hiding, and never hide an alarm. hiddenCount is required and exact.
Menu
menu
Contextual actions with destructive items separated and last. Destructive items are separated and last.
Button
button
Buttons and button groups. Split out of toolbar, whose install command was the only way to get one while the Button page offered none. children is required — nothing is icon-only. disabled is not a prop; unavailable takes the reason.
Toolbar
toolbar
One tab stop with arrow-key traversal. Depends on button, so installing it still brings its buttons. Actions never rearrange themselves — nothing reorders on use.
Tooltip
tooltip
Supplementary only, with keyboard parity. Never the sole carrier of anything. aria-describedby, never aria-labelledby.
Masthead
masthead
The application bar: product name, environment banner, signed-in user. The environment banner cannot be switched off in a non-production build.
Side navigation
side-nav
A nav list whose counts say what they count. The current item is marked, not merely coloured.
Breadcrumb
breadcrumb
The trail, as data. A crumb cannot be a control that does something.
View heading
view-heading
Names the view and sets the document title. The browser tab says which patient is open.
App layout
app-layout
The shell, with a docked alarm region that never scrolls away. Ships with SkipLink, which points at the main region the layout renders.
Split pane
split-pane
A two-pane split for one screen. Not part of the application shell.
Panel
panel
A titled container. Lived in the accordion item, then the layout item; it is neither.
Date & time picker
date-picker
Clinical time: zone-aware, and carrying the precision it was known to. Asks how well the time is known before asking what it is.
Device identification panel
device-label
MDR/IVDR identification: intended purpose verbatim, UDI, manufacturer, notified body. An absent notified body is stated, not left blank.

Do's and don'ts

Do

Install foundations, then take the components you need.

The token contract is the part that carries safety meaning. The components are conveniences built on top of it.

Don't

Copy a component and leave the tokens behind.

The alarm hues then become whatever your theme says, which is the one thing the parity contract exists to prevent.

Do

Read a missing prop as the rule it encodes.

Badge has no max because a capped count is a lie with a plus sign on it. The absence is the design.

Don't

Fork it to put the prop back without saying why.

Entirely possible, which is why this is a reference implementation rather than a control. If you add it, record the reasoning.

Do

Run your own accessibility and usability evaluation.

Installing this performs no part of your IEC 62366-1 file. The checklist is where to start.

Don't

Cite the registry as evidence of conformity.

It is an argument, not evidence. The manufacturer validates under MDR or IVDR regardless of what was installed.

NotJustAnyMed.Tech Design System · The component registry · v1.0 · draft for review
A reference implementation of the rules, not a validated library and not evidence of conformity.