TestModeBadge
What it is
<TestModeBadge> is the dashboard surfaces' visual guard for non-live
resources. Render it next to every document, signing envelope, render
job, or audit entry whose mode is test or sandbox so the user
cannot mistake test-mode artifacts for production output.
Three independent guards make the contract defensible (plan §3.5):
- PDF watermark — every page of a non-live document carries the
TEST · DO NOT FILE · sig <fp>diagonal banner at 30% opacity. - Cryptographic key separation — test signatures cannot validate against live keys.
- This badge — the UX guard.
The three surfaces use the same ·-separated three-token copy
format so a user who learns the convention from the banner
recognizes it on the badge and the watermark. Microcopy contract
lives in @repo/templates/copy/dashboard-strings.ts; this component
inlines the defaults to keep @matter/components a leaf in the dep
graph (no workspace circular dep).
Voice rule
Declarative. Never a question. The hint copy elsewhere
(hint_customize_default) follows the same rule.
TEST · Sandbox · Documents are not legally binding
Avoid: "Are you sure this is test mode?" Avoid: "Test mode active — heads up!"
When to render
Render the badge whenever the underlying resource is non-live. The
canonical prop is mode — pass the resource's mode field directly so
the badge can distinguish sandbox (SBX) from test (TEST):
import { TestModeBadge } from "@matter/components";
<TestModeBadge mode={document.mode} />When mode is "live", the component returns null — never
?-conditional the import. Wrap every document list-row, detail page,
preview thumbnail, and the sidebar mode indicator.
The legacy livemode: boolean prop is still accepted for SDK
back-compat (livemode={true} → live, livemode={false} → test) but
it cannot express sandbox. New call sites should pass mode.
Sizing
size="sm" (default) — list rows + chrome.
size="md" — detail-page hero, near the primary title.
Anatomy
A single <span role="status"> with the canonical recipe (.tmb +
.tmb-{size}). The visible label is TEST; the full banner copy is
attached via title (tooltip) and aria-label (screen reader).
Drift guard
A regression test at
packages/templates/test/test-mode-badge-copy.test.ts asserts the
inline defaults here match TEMPLATES_COPY in
packages/templates/src/copy/dashboard-strings.ts. Updates require
editing both — CI fails if they diverge.
Color token
Amber, matching apps/app/app/(authenticated)/components/mode-banner.tsx's
--role-amber. Round-2 design audit fix: destructive (red) is
reserved for irreversible actions like dissolution; test-mode is
advisory, so it gets amber.