DisclaimerNote
The short standing note saying this is information, not medical advice. It is placed by rule, so it is always in the same place and never in the way.
Preview
disclaimer-note · base base · style base-lyraOpen under the product themeInstallation
pnpm dlx shadcn@latest add @opsinjs/disclaimer-note
The @opsinjs namespace is declared in your components.json. Everything it installs is code you then own. There is no runtime package to keep in step.
Usage
import { DisclaimerNote } from "@/components/ui/disclaimer-note"<DisclaimerNote placement="footer">
The product's own two sentences go here. opsinjs ships none of them.
</DisclaimerNote>When to use it
Use it when
- Any surface that shows a health value, range, status or derived score to the person it belongs to.
- The end of a flow that gathered health information, where the reader may expect an assessment they will not get.
- Wherever a product could be mistaken for a clinical service, such as a symptom questionnaire or a result summary.
Do not use it when
- The reader needs to do something now, and the note would sit above the instruction.Use
care-cardinstead. - The message is specific to one result rather than a standing statement about the product.Use
calloutinstead. - Something has changed and needs the reader's attention.Use
alert-bannerinstead. - You are explaining a word rather than the product's limits.Use
terminstead. - The reader must acknowledge the statement before continuing, and the product needs a record of it.Use
consent-sheetinstead.
Clinical meaning
Asserts. That the product provides information rather than clinical assessment, does not replace a clinician's advice and, where relevant, is not a medical device. The component supplies position, type size, ink and boundary, and none of the content.
Never read as. A waiver or a substitute for designing safely: a disclaimer does not make an unsafe screen safe. It is never this number is unreliable, since the note is about the product's role, not the measurement. The safety review checklist judges the screen.
Colour axis. Neither. There is no status or category prop, no data-status or
data-category, and no fill. See
The two colour axes.
Thresholds. None. No clinical number is written into the component and none passes through it: no threshold, reference range, score band or staleness boundary.
Words. The consuming product's, under the clinical interaction guidelines. opsinjs ships no legal text: no default string, no placeholder, no vetted variant and no translation fallback. Regulatory context sets out what DCB0129, DCB0160, the EU MDR and FDA SaMD ask of the product.
Anatomy
DisclaimerNoteThe root, outside both colour axes: no status or category prop, no fill, no role, no live region.Controlled byplacementDisclaimerNote.IconOptional, off by default, decorative and aria-hidden. The glyph is fixed, so it is never a warning triangle.Controlled byiconDisclaimerNote.TextThe product's one or two sentences, at body size in body ink. Prints an admission when nothing is supplied.Controlled bychildrenDisclaimerNote.LinkThe fuller statement. Label and href arrive as one object, and a vague label warns in development.Controlled bymoreDisclaimerNote.VersionThe wording's id, rendered exactly as written at footnote size in secondary ink.Controlled bytextVersion
Examples
One note, at the foot of the surface
Three rows and one placement="footer" note under all of them: not one per row, and
never above them.
disclaimer-note-once-at-the-foot-of-a-surface · base base · style base-lyraOpen under the product themeWhen nobody wrote the words
Copy from a content service can arrive empty. children of undefined, false, 0,
an empty array or whitespace prints an admission and warns in development. Copy in an
element is taken at its word.
disclaimer-note-no-text-supplied · base base · style base-lyraOpen under the product themeContent guidelines
Two sentences at most: what the product does, then what it does not do. Use plain words, this app rather than the Service, and the job title a reader recognises. Name the link for where it goes, because learn more raises a development warning.
Do
Name what the product does, then the one limit that matters most, one sentence each, in the product's register.
Don’t
Open with the trading name, stack abstract nouns for what it is not, and close by placing reliance on the reader.
Accessibility
Audited against WCAG 2.2 AA. A source pass and a rendered pass, author-run rather
than independent, clinical review still pending. The rendered pass on
/view/base/base-lyra/component/disclaimer-note was clean: zero axe violations, the
link kept its target floor, focus-visible held, and nothing scrolled sideways at 320px
or 200% text. Nothing in the source needed changing. The standing guarantees hold: type
sizes and colours are role tokens, the decorative glyph is aria-hidden, the statement
is a real paragraph, and the only interactive element is a real anchor that warns on
unhelpful labels.
One deferred item. The root is a plain <div> with no role and no accessible
name, so a screen reader meets the note as ordinary sentences rather than a bounded
"note". Reading order and content are fully conveyed, so this is not an AA failure. The
boundary is an enhancement left out on purpose: a role is a spec decision reserved to
review, and an aria-label would inject an English string into a translation-neutral
component. Standing gates still cover its one string on every commit: no px type size,
no raw colour literal, no banned word.
| Key | Action | Notes |
|---|---|---|
| Tab | Moves to the link, when there is one | The note is text, not a tab stop. The link is the only focusable part. |
| Shift+Tab | Moves back out of the link | One stop, so reverse order matches visual order. |
| Enter | Follows the link | An ordinary anchor, so modifier-clicks keep the browser's behaviour. |
| Space | Scrolls the page, as it does anywhere else | Nothing here captures Space. |
| Pair | Theme | APCA Lc | WCAG 2.2 | Floor |
|---|---|---|---|---|
| body text on the page | light | 101.6 | 17.18:1 | Pass |
| body text on the page | dark | -100.5 | 18.00:1 | Pass |
| body text on a card | light | 104.7 | 17.96:1 | Pass |
| body text on a card | dark | -99.6 | 16.32:1 | Pass |
| body text on the muted ground | light | 98.1 | 16.32:1 | Pass |
| body text on the muted ground | dark | -97.5 | 13.77:1 | Pass |
| secondary text on the page | light | 83.9 | 7.42:1 | Pass |
| secondary text on the page | dark | -80.7 | 13.44:1 | Pass |
| secondary text on a card | light | 87.0 | 7.76:1 | Pass |
| secondary text on a card | dark | -79.8 | 12.19:1 | Pass |
| secondary text on the muted ground | light | 80.4 | 7.05:1 | Pass |
| secondary text on the muted ground | dark | -77.8 | 10.28:1 | Pass |
| a hairline boundary on the page | light | 19.3 | 1.41:1 | Below floor |
| a hairline boundary on the page | dark | -8.2 | 1.90:1 | Below floor |
| a hairline boundary on a card | light | 22.4 | 1.47:1 | Below floor |
| a hairline boundary on a card | dark | -7.3 | 1.72:1 | Below floor |
| a hairline boundary on the muted ground | light | 15.8 | 1.34:1 | Below floor |
| a hairline boundary on the muted ground | dark | 0.0 | 1.45:1 | Below floor |
| a placeholder boundary on the page | light | 69.8 | 4.52:1 | Pass |
| a placeholder boundary on the page | dark | -51.0 | 7.62:1 | Pass |
| a placeholder boundary on a card | light | 72.8 | 4.72:1 | Pass |
| a placeholder boundary on a card | dark | -50.1 | 6.91:1 | Pass |
| a placeholder boundary on the muted ground | light | 66.2 | 4.29:1 | Pass |
| a placeholder boundary on the muted ground | dark | -48.1 | 5.83:1 | Pass |
| a placeholder fill on the page | light | 8.3 | 1.18:1 | Below floor |
| a placeholder fill on the page | dark | -8.2 | 1.90:1 | Below floor |
| a placeholder fill on a card | light | 11.4 | 1.23:1 | Below floor |
| a placeholder fill on a card | dark | -7.3 | 1.72:1 | Below floor |
| a placeholder fill on the muted ground | light | 0.0 | 1.12:1 | Below floor |
| a placeholder fill on the muted ground | dark | 0.0 | 1.45:1 | Below floor |
| a placeholder boundary on its own fill | light | 58.9 | 3.84:1 | Pass |
| a placeholder boundary on its own fill | dark | -41.5 | 4.01:1 | Below floor |
| the card hairline on the page | light | 69.8 | 4.52:1 | Pass |
| the card hairline on the page | dark | -28.7 | 4.19:1 | Below floor |
| the card hairline on a card | light | 72.8 | 4.72:1 | Pass |
| the card hairline on a card | dark | -27.9 | 3.80:1 | Below floor |
These are the measured token pairs this component draws colour from, not a measurement of the component itself.
API reference
Prop
Type
Generated from DisclaimerNoteProps in registry/bases/base/disclaimer-note.tsx.
children is typed optional and required by the contract, so the missing state can
render and print its admission. placement changes only the space above the note, and
there is no top value: never above the result. There is no default text and no
colour prop, and an axis class through className raises a development warning.
Related
- Callout is information about the content. A disclaimer is about the product.
- AlertBanner is entitled to speak; styling a disclaimer as one is the commonest mistake.
- ConsentSheet is a request the reader answers, not a statement they read.
- CareCard is an instruction with an author. A disclaimer asks for nothing.
ConsentSheet
A sheet that asks permission for one specific thing at a time, explains what it is for, and makes saying no or changing your mind as easy as saying yes.
SourceCitation
Where a piece of health information came from, in plain words, with an optional link to the fuller citation and an optional date it was last checked.