Snippets /

Primary button

Every state covered: hover, focus-visible, active, disabled.

Widely supported
ui

Quick implementation

.btn-primary {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0.65rem 1.5rem;
  font: 600 0.9rem/1.2 system-ui, sans-serif;
  color: white;
  background: oklch(0.52 0.22 265);
  border: none;
  border-radius: 0.5rem;
  cursor: pointer;
  transition:
    background 0.2s ease-out,
    box-shadow 0.2s ease-out,
    transform 0.1s ease-out;
  box-shadow: 0 1px 3px oklch(0 0 0 / 0.12);
}

.btn-primary:hover {
  background: oklch(0.48 0.22 265);
  box-shadow: 0 2px 8px oklch(0 0 0 / 0.18);
}

.btn-primary:active {
  transform: scale(0.97);
}

.btn-primary:focus-visible {
  outline: 2px solid oklch(0.52 0.22 265);
  outline-offset: 3px;
}

.btn-primary:disabled {
  opacity: 0.45;
  cursor: not-allowed;
  pointer-events: none;
}

Prompt this to your LLM

Includes role, constraints, state coverage, and variants.

You are a senior frontend engineer building a button component.

Goal: A production-ready primary button covering all interactive states.

Technical constraints:
- Use oklch() for background color — oklch(0.52 0.22 265) as base.
- Hover: darken by reducing lightness (oklch(0.48 ...)).
- Active: scale(0.97) for tactile press feedback.
- Focus-visible: 2px solid outline with 3px offset — NOT visible on mouse click.
- Disabled: opacity 0.45, cursor: not-allowed, pointer-events: none.
- Use display: inline-flex + align-items/justify-content for icon alignment.
- Transition: background 0.2s ease-out, box-shadow 0.2s ease-out.
- Layered box-shadow for subtle depth.

Variants to include:
A) Primary (filled).
B) Ghost (transparent background, border, text-colored).
C) Small and large size variants.

Return CSS. No JavaScript.

Why this matters

Buttons are the most interacted-with element on any page, yet most are missing states. A production button needs five states: default, hover, active (pressed), focus-visible (keyboard), and disabled. Skipping any of these creates a broken experience for some users. This snippet covers them all in ~30 lines.

The logic

The oklch() color space makes state variations trivial — just reduce lightness for hover. scale(0.97) on :active gives tactile feedback without layout shift. :focus-visible shows the outline only for keyboard users, not mouse clicks. pointer-events: none on disabled prevents all interaction including tooltips from parent wrappers.

Accessibility & performance

The white-on-accent contrast ratio should be at least 4.5:1 for WCAG AA. oklch(0.52 0.22 265) on white text passes. The :focus-visible outline must be visible — use a contrasting color with offset. Never remove the outline without replacing it. Transitions use compositor-friendly properties for smooth 60fps interaction.