SecurityV0 · Component catalog
Every primitive in shared/components.jsx. What it's for, what props it takes, and when not to use it.
The rules exist because the design system is append-only (per §5 of the working agreement): new surfaces should compose these primitives rather than invent new ones. If a component is missing, add it here first and get sign-off.
Navigation chrome
<Sidebar active />
Left rail with brand mark, environment label, primary nav, admin nav, and the reviewer's identity at the bottom.
| Prop | Type | Notes |
|---|---|---|
active | "overview" | "clusters" | "chains" | "exposures" | "drift" | "inventory" | Which nav item is highlighted. |
Don't add more top-level nav items without a corresponding top-level surface. The nav mirrors the information architecture, not product taxonomy.
<Topbar crumbs />
Thin breadcrumb bar with the environment and last-sync label on the right.
| Prop | Type | Notes |
|---|---|---|
crumbs | string[] | In order, root → leaf. The last crumb renders in on-surface color. |
The topbar is 48px, no icons, no buttons. Actions live inside the page body.
Status signals
<SeverityChip severity />
Colored pill for severity. "critical" is red, "high" is amber, anything else is the warn slate.
<ActivityChip activity />
Runtime state, not severity:
"Active"→ teal "Execution confirmed""Dormant"→ slate "Dormant · standing authority"- anything else → slate "Standing authority"
Never conflate severity and activity — a dormant path can still be critical, and an active path can be low-severity.
<EvidenceChip state />
What kind of evidence backs the claim:
"proven" | "confirmed"→ teal"standing"→ slate "Evidence · standing authority""dormant"→ slate "Evidence · dormant"- anything else → dim
This is the companion to ActivityChip. Use on lists where the row's evidence strength matters more than its runtime state (e.g. exposures.html).
<SeverityDot severity />
Monochrome-safe severity signal: a small square + uppercase label. Used in list headers and cluster rows, where a full chip would be visually heavy.
<FounderCopyBadge /> · <DraftPendingBadge />
Disclose copy provenance. FounderCopyBadge is teal ("Founder copy"); DraftPendingBadge is slate ("Draft pending"). One of these must accompany any <Placeholder> block on a brief.
Content primitives
<Placeholder block>{copy}</Placeholder>
The marker for [founder draft pending] copy. Renders diagonal hatched background behind the text, italic, surface-toned — visible but not alarming. Pass block for a block-level placeholder, otherwise it's inline.
Use when: the layout needs prose that the founder hasn't written. The tool lays out; the writer fills.
Don't use: to gloss over a decision that hasn't been made. If a decision is open, note it in QUESTIONS.md.
<Kicker tone />
Uppercase, letter-spaced eyebrow above a headline. Tones: "primary" (slate), "muted" (outline), default is tertiary (red — only for live posture).
<Dateline /> · <LabelMeta tone />
Tiny uppercase labels. Dateline is for time/location tags; LabelMeta is for field labels inside cards. Both share the same typography; the split is semantic.
Layout primitives
<MetricTile label value note tone />
A single metric tile. Value-first, label as caption, note below. tone can be "danger", "warn", or omitted.
Don't use when three or more tiles would create a "KPI strip" feel. Prefer a sentence that names the metric in context.
<ChainDiagram chain compact />
Horizontal access-chain diagram. Nodes render on a dot-grid surface with an arrow between each pair.
| Prop | Type | Notes |
|---|---|---|
chain | { kind, label, sub, danger? }[] | Nodes render left-to-right in order. kind is one of workload, identity, connection, resource. |
compact | boolean | Tighter padding for side-rail use. |
Always horizontal, per DESIGN.md. Never draw a diagonal, never infer an edge the graph didn't provide.
Action
<ActionTracker story tracked owner target lastUpdate />
Right-rail card for the "safest first action" on a brief or chain page. Two states:
tracked={true}→ teal chip "Tracked", owner/target/last-update trio.tracked={false}→ slate "Untracked" chip + primary "Track action" button.
| Prop | Type | Notes |
|---|---|---|
story | story object | Provides the action text. |
tracked | boolean | Toggles the two states. |
owner / target / lastUpdate | string | Only shown in tracked state. |
The tracker is the only component that claims action status. List rows link to it; they never show their own "Tracked" badge that the tracker hasn't blessed.
State primitives
<Skeleton w h r style />
Flat rectangle for loading shape. No shimmer (per §4.4). w/h are CSS values; r is a border radius in px (defaults to 2).
<EmptyState title sentence lastScan /> · <ErrorState title sentence lastScan />
The two negative-space templates. Both are deterministic:
EmptyStatesays why there's no data and cites the last successful scan time.ErrorStatesays data is withheld, not partially shown, and offers retry + diagnostics.
Copy is per-surface; see StateOverride below for the lookup table.
<StateOverride surface lastScan />
Top-level switch based on the ?state= query param. Returns <EmptyState>, <ErrorState>, a shape-skeleton, or null. Every page wraps its main content like:
{qs("state") ? <StateOverride surface="overview" lastScan="4m ago" /> : <MainContent />}
surface is one of "overview" | "brief" | "chain" | "clusters" | "exposures" | "drift" and picks the right per-surface copy.
Tweaks
<Tweaks controls values onChange />
Floating ⚙ panel bottom-right. Each control is a segmented button group.
useTweaks(pageKey, defaults)
Hook that persists tweak state to localStorage under sv0-tweaks-<pageKey>. Returns [values, setKey].
Keep the surface small. A Tweaks panel with more than four controls means the design has unresolved choices; resolve them in the main UI, not in a control panel.
Utilities
qs(name)
Read a URL query param. Returns null if missing. Used for ?state=, ?variant=, ?print=1, and ?story=.
What's intentionally missing
These do not exist, and adding them needs a written justification:
- Charts / gauges / dials. Posture is a sentence. See UX-GUIDE §5.1.
- Toast notifications. Every action routes through the tracker or the ticket path, not a transient banner.
- Confirmation modals. The only destructive action in the pilot is "Revoke access," and it has a dedicated route — not a modal.
- Icon-only buttons. Every button has a verb.
- Borderful cards. Separation is tonal (per DESIGN.md's no-line rule).
outline-variantonly renders at low opacity for hair-rules inside dense tables.
If you think you need one of these, write the reason in QUESTIONS.md before adding it.