Skip to main content

Component Variants

Production variants for core Jj* primitives. Naming: role via props — never TealButton.

Pattern: Jj{Domain}{Element} · states: default | hover | focus | active | disabled | loading | success | caution | error


Button — JjButton​

VariantUseVisual
primaryMain CTA (Approve send, Save)Accent fill, text-on-accent
secondarySecondary actionsSurface + border-default
ghostTertiary / toolbarsTransparent; hover muted
dangerDestructive (Delete draft)Danger fill or outline
successRare explicit success actionJade — prefer toast instead
SizeHeightTypePad X
sm28pxsmall-emphasisspace-3
md32pxsmall-emphasisspace-4
lg40pxbody-emphasisspace-5

Radius: md. Loading: spinner + disabled semantics. Icons: icon-sm/md, gap space-2.


Icon button — JjIconButton​

Same variants as ghost/secondary by default. Hit target ≥ 32×32. Must have accessible name.


Input — JjInput / JjTextarea / JjSelect​

StateBorderRing
defaultborder-default—
hoverborder-strong—
focusaccentfocus-ring
errordangerdanger muted
disabledsubtle— muted text

Size md default (height 32). Radius sm. Label: label.field above, gap space-2.


Badge / pill — JjBadge​

ToneUse
neutralCounts, tags
accentHighlights
successSent
cautionFollow-up due, pending
dangerFailed send
SizeType
smtiny
mdsmall

Privacy: use JjAgentPrivacyPill (not generic badge) for on-device agent status.


Agent privacy pill — JjAgentPrivacyPill​

  • Radius: pill
  • Colors: privacy-pill-* tokens
  • Text: “Agent · On-device” / “Agent ready” / “Agent unavailable” (honest)
  • Optional status pulse when ready
  • Always meaningful to AT (aria-label)
  • Do not default label to “LLM”

Remote user-configured runtime: different honest label — never spoof on-device.


Alert / callout — JjAlert​

ToneLive regionUse
infopoliteNeutral tips
successpoliteQuiet confirmations
cautionpoliteFollow-up / approval needed
dangerassertiveErrors with recovery

Structure: icon + title + body + optional action. No metaphor in danger titles.


Toast — JjToast​

Mirrors alert tones. Elevation lg. Motion: toast rise. One primary action max.


List row — JjListRow / JjApplicationQueueRow​

StateBackground
defaulttransparent
hoverbg-muted / alpha wash
selectedaccent-muted
focus-visiblefocus ring

Padding: space-3 / space-4. Row settle on insert. No card chrome required.


Tabs — JjTabs​

Underline or subtle segmented control. Active: text-primary + accent indicator. Avoid pill-cluster tab bars.


Switch / checkbox — JjSwitch / JjCheckbox​

Accent when on. Label describes enabled state (“Require approval before send”).


Radius lg, shadow lg, scrim. Title h3. Primary + secondary actions. Focus trap; Esc closes when safe.


Empty state — JjEmptyState​

Icon/illustration icon-lg + title + one sentence + one primary CTA. See brand empty-state copy.


Agent status — JjAgentStatusBadge​

Idle / running / paused / failed. Idle copy may use brand microcopy; failed stays plain.


Variant rules​

  1. Encode role (primary, caution), not color names.
  2. Destructive always danger + explicit label (“Delete draft”).
  3. Don’t invent streak or urgency variants.
  4. Compose domains: JjFollowUpCard uses JjBadge tone=caution, not a one-off orange card system.