Caption

Says what a figure shows and where its data comes from, so every number and screen on the site can be checked.

Atom · stable · v1.1.0 · owner: Site system lead · contract 19 of 20 points (open: figma)

Do and don't

Do: Honesty caption for sample data

Rendered by caption.ts

Open example: Caption · Do: Honesty caption for sample data Use the full-page example to follow page links.

The data is not live, and the caption says so.

Do: A data note with its file

Rendered by caption.ts

Open example: Caption · Do: A data note with its file Use the full-page example to follow page links.

The claim is one click from its evidence.

Do: Native caption association

Rendered by caption.ts

Open example: Caption · Do: Native caption association Use the full-page example to follow page links.

Retains native caption identity without changing layout or words.

Don't: A vague label

Rendered by caption.ts

Open example: Caption · Don't: A vague label Use the full-page example to follow page links.

It does not say whether the data is real.

Don't: Marketing in a caption

Rendered by caption.ts

Open example: Caption · Don't: Marketing in a caption Use the full-page example to follow page links.

A caption states the source; it never sells.

Generated API variants, rendered live

Generated variants of the first authored example, from selected boolean and enum props. These are API explorations, not authored state declarations or verification results. Hover and focus respond to the pointer and the keyboard in the examples above.

Base authored example

Rendered by caption.ts

Open example: Caption · Do: Base authored example Use the full-page example to follow page links.

The data is not live, and the caption says so.

state: live

Rendered by caption.ts

Open example: Caption · Do: state: live Use the full-page example to follow page links.

In the live state.

state: mixed

Rendered by caption.ts

Open example: Caption · Do: state: mixed Use the full-page example to follow page links.

In the mixed state.

state: dev

Rendered by caption.ts

Open example: Caption · Do: state: dev Use the full-page example to follow page links.

In the dev state.

Rules

RuleWhyCheck
Native IDs/classes belong to the caller; source language does not translate content or add live announcements.Compatibility retains existing semantics.Automated: tests/unit/frame-api-compatibility.test.ts
Every figure, screenshot and showcase has a caption.A picture without its source cannot be checked, and the site promises everything can be.Automated: scripts/site/system/compose.ts (figure without figcaption)
Sample, synthetic or recorded data says so in the caption.The reader must never mistake a demo for a client's live data (AGR-0001 truthfulness).Automated: site-claims test and the honesty-caption content tokens
One caption component; no element defines its own caption style.Fifteen caption styles made the site look unplanned (inventory, 26 Oct).Automated: scripts/site/system/check.ts (caption classes owned only by caption and figure elements)

API

PropTypeRequiredDefaultWhat it does
idstringNoCaller-owned native caption ID; no generated IDs.
langen | jaNoExplicit source language.
extraClassstringNoExisting native component caption classes, retaining their owning styles.
htmlhtmlYesWhat it shows and where the data comes from; may contain a text link to the data.
kinddefault | honesty | source | dataNo"default"Default for figures, honesty for sample data, source for a cited source, data for a data note.
labelstringNoA bold lead such as 'Data:'.
claimstringNoThe claims-register id the honesty caption speaks for (data-claim).
statelive | mixed | devNoThe claim's state, for the honesty variant.
tagp | figcaption | spanNo"p"figcaption inside a figure.

Contract details

The full contract: identity, anatomy, variants, states, tokens, layout, motion, accessibility, content, tests

Identity

AspectValue
Idcaption
LayerAtoms
Categorytypography
OwnerSite system lead
Statusstable
Version1.1.0
Sourceapps/showcase/site/system/atoms/caption.ts (private repository; the contract and the render function are this one module)
VersionDateChange
1.1.02026-10-29Add native caption identity and source-language forwarding; defaults unchanged.
1.0.02026-10-26One caption for every figure, showcase and data line, with an honesty variant for sample data.

Use when

  • Under every figure, diagram, screenshot and showcase. Why: A picture without its source is a claim nobody can check.
  • When data is sample or synthetic. Why: The honesty variant says so in the same place every time (D-SITE-007).

Do not use when

  • For body copy. Why: Captions are small; the argument belongs in the text.
  • To hide a limitation. Why: Limits are stated plainly; a caption never softens them.

Anatomy

PartWhat it is
rootfigcaption, p.data-note, p.source or span.demo-source.
labelAn optional bold lead ('Data:').
textWhat it shows and where the data comes from.

Made of: tokens:type, tokens:colour, text-link.

Used in: figure-frame, stat, academy-lesson, agent-check, autonomy-demo, before-after, cloth-diagram, conformance-table, contract-excerpt, conversations, cost-calculator, coverage-map, decision-list, design-md-excerpt, drift-hero, drift-palette, first-90, flow-diagram, flow-layers, identity-motion, layers-demo, ops-board, product-screen, proof-shift, read-your-stylesheet, replay, repo-change, repo-tree, roles-picker, score-us, showcase-frame, stage-finder, system-of-systems, takenote-card, token-chain, problem-section.

Variants

VariantWhenWhy
defaultA figure's description.Small, secondary ink, under the figure.
honestySample, synthetic or recorded data.Bold, so the reader cannot miss that the data is not live.
sourceA cited study or report.The reader can find the source.
dataA data file behind a page.The file is named and linked.

States

StateRendered or not applicable
defaultdefault
hoverNot applicable: A caption is not interactive, so it has no hover state.
focus-visibleNot applicable: A caption does not take focus; links and buttons inside it carry their own focus ring.
activeNot applicable: A caption cannot be pressed.
disabledNot applicable: A caption has nothing to disable.
loadingNot applicable: A caption is rendered at build time and is complete when the page loads.
emptyNot applicable: A caption is not rendered without content; the builder skips it.
errorNot applicable: A caption shows no data that can fail.
currentNot applicable: A caption has no current item.
visitedNot applicable: A caption is not a link.
expandedNot applicable: A caption does not open or close.

Tokens

PartToken
root.font--type-small (honesty: --type-small-strong)
root.color--ink-2; --field-fg-2 on a field
--caption-font-type-smallvar(--type-small)
--caption-color-ink-2var(--ink-2)
--caption-color-inkvar(--ink)
--caption-font-type-small-strongvar(--type-small-strong)
--caption-font-size-fs-smallvar(--fs-small)
--caption-margin-top-space-5var(--space-5)

Layout

AspectValue
max60 characters
breakpointsRequired review at 390, 768, 1024 and 1440 px; execution is not implied by this declaration; same everywhere.
wrappingWraps; long file names break anywhere.
textExpansionGrows downwards; captions have no fixed height.

Spacing and rhythm

AspectValue
internalNone.
external--space-4 below its figure.
rhythmAlways directly after the figure it describes.

Motion

AspectValue
NoneStatic text.

Runtime and reuse

  1. Render-only element; mount any registered child enhancements separately. Preserve required Site CSS, fonts, responsive and locale rules from nativeElement.

Accessibility passport

AspectValue
rolefigcaption gives the figure its description; otherwise a paragraph
nameIts text
keyboardNot interactive (links inside are).
focusNot focusable.
screenReaderRead after the figure; the figure is labelled by it.
contrast--ink-2 on cotton 8.6:1; field secondary text 4.5:1 or better.
targetNot a target.

Content

SlotLengthVoice
html2 sentencesWhat it shows, then where the data comes from: 'Sample data', 'Recorded server output', 'Real audit output'

Good: “Real audit output, scored with Loom's own open rubric.” · “Sample data. The organisation and its rules are made up.”

Bad: “Illustrative” · “Powered by AI”

Japanese: The existing caption.sample, caption.scripted and caption.real-output tokens have Japanese AI drafts pending native review. Recorded-source captions retain their consuming element's wording; they are not relabelled as scripted examples.

Icons and illustrations

None: this element uses no icon or illustration of its own.

Decisions and exceptions

Usage

29 uses across the built pages (measured by npm run site:system).

Tests

AspectValue
unittests/unit/site-system.test.ts: renders every do and don't example through the registry and checks the classes it owns
visualNot yet: there are no screenshot baselines; the Library page is checked for sideways scroll at 1440 px by tests/site/system.spec.ts
a11ytests/site/system.spec.ts: axe (0 serious or critical) on the element's Library page in light and dark
parityscripts/site/system/check.ts: Library examples are rendered by the same render function the site imports

Figma

not-yet: The Loom Site Figma library is the last stage of the plan; this element is not mapped yet.

Open in Storybook

Start with a conversation about your system.

We read your system, show you what we found, and agree with your team what to fix first.