Buttons & CTAs
10 variants · 8 sizes · 5 interaction states. All documented with exact token values. Built on shadcn/ui CVA with CPSL design tokens.
All Variants — Live Interactive
Real Button components — hover, click, and Tab through them to see all states in action.
Interaction States — Documented
Default
Resting state. No interaction.
:hover
bg opacity → 88%. Cursor: pointer.
:focus-visible
3px ring · ring-ring/50 · #697279 at 50%.
:active
bg opacity → 82%. scale(0.98).
:disabled
opacity-50 · pointer-events-none.
Primary (default)
opacity(bg) → 88%
3px · #697279 · 50% alpha
opacity(bg) → 82% + scale(0.98)
opacity-50 · no events
cpsl-crimson
opacity(bg) → 88%
3px · #697279 · 50% alpha
opacity(bg) → 82% + scale(0.98)
opacity-50 · no events
Secondary
opacity(bg) → 88%
3px · #697279 · 50% alpha
opacity(bg) → 82% + scale(0.98)
opacity-50 · no events
Ghost
opacity(bg) → 88%
3px · #697279 · 50% alpha
opacity(bg) → 82% + scale(0.98)
opacity-50 · no events
Destructive
opacity(bg) → 88%
3px · #697279 · 50% alpha
opacity(bg) → 82% + scale(0.98)
opacity-50 · no events
Focus Ring — Keyboard Navigation
Tab to focus these buttons →
Press Tab to cycle through buttons and see the live focus ring.
Focus ring anatomy
State CSS Reference
/* ── State tokens for Primary button ──────────────────────── */
/* Default */
.btn-primary {
background-color: var(--primary); /* #697279 */
color: var(--primary-foreground); /* #ffffff */
}
/* Hover */
.btn-primary:hover {
background-color: color-mix(in srgb, var(--primary) 88%, transparent);
}
/* Focus (keyboard only) */
.btn-primary:focus-visible {
box-shadow: 0 0 0 3px oklch(from var(--ring) l c h / 50%);
/* ring = #697279 → rgba(0,71,255,0.5) */
}
/* Active / Pressed */
.btn-primary:active {
background-color: color-mix(in srgb, var(--primary) 82%, transparent);
transform: scale(0.98);
}
/* Disabled */
.btn-primary:disabled {
opacity: 0.5;
pointer-events: none;
cursor: not-allowed;
}Sizes
Icon Buttons
Common Patterns
Primary + Secondary CTA
Match Actions
Destructive Confirm
Implementation
import { Button } from "@/components/ui/button"
// Core CPSL variants
<Button variant="default">Primary</Button>
<Button variant="cpsl-crimson">Crimson CTA</Button>
<Button variant="cpsl-navy">Navy</Button>
<Button variant="secondary">Secondary</Button>
<Button variant="ghost">Ghost</Button>
<Button variant="destructive">Destructive</Button>
<Button variant="cpsl-success">Success</Button>
<Button variant="cpsl-live">Live Match</Button>
// Sizes
<Button size="xs" /> // h-6
<Button size="sm" /> // h-8
<Button size="default" /> // h-9
<Button size="lg" /> // h-11
<Button size="xl" /> // h-13
<Button size="pill" /> // h-9 · rounded-full
<Button size="pill-lg" /> // h-11 · rounded-full
// Disabled
<Button disabled>Disabled</Button>