Skip to content
ComponentsTestModeBadge

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):

  1. PDF watermark — every page of a non-live document carries the TEST · DO NOT FILE · sig <fp> diagonal banner at 30% opacity.
  2. Cryptographic key separation — test signatures cannot validate against live keys.
  3. 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.

On this page