The Kit/Components/Button

Button

Primary, secondary and ghost actions in three committed languages: instrument pill, broadsheet plate, painted poster block. Self-contained, theme-aware, copy one file.

theme-aware · one self-contained file per variantMIT · copy freely

Apex

Racing-instrument console on layered indigo · proven in F1Peak · see the whole Apex set
loading…
Apex.tsx
"use client";
import * as React from "react";

/* Apex Button - racing-instrument pill: mono caps, accent fill with a soft signal
   bloom (this family's shipped look), outline + ghost steps. Colour from theme vars. */

const INK_ON_ACCENT = "#06070d";

type Variant = "primary" | "secondary" | "ghost";

const base: React.CSSProperties = {
  display: "inline-flex", alignItems: "center", justifyContent: "center", gap: 7,
  fontFamily: "var(--font-mono)", fontWeight: 600, fontSize: 11.5, lineHeight: 1,
  textTransform: "uppercase", letterSpacing: "0.12em", whiteSpace: "nowrap",
  padding: "8px 16px", borderRadius: 999, border: "1px solid transparent",
  cursor: "pointer", transition: "background .16s ease, border-color .16s ease, color .16s ease, box-shadow .16s ease, filter .16s ease",
};

export function Button({
  variant = "primary", children, style, ...rest
}: React.ButtonHTMLAttributes<HTMLButtonElement> & { variant?: Variant }) {
  const [h, setH] = React.useState(false);
  const v: Record<Variant, React.CSSProperties> = {
    primary: {
      background: "var(--accent)", color: INK_ON_ACCENT,
      boxShadow: `0 0 18px -2px color-mix(in srgb, var(--accent) ${h ? 72 : 55}%, transparent)`,
      filter: h ? "brightness(1.06)" : "none",
    },
    secondary: {
      background: h ? "color-mix(in srgb, var(--accent) 14%, transparent)" : "transparent",
      color: "var(--accent)", border: "1px solid color-mix(in srgb, var(--accent) 42%, var(--line))",
    },
    ghost: {
      background: h ? "color-mix(in srgb, var(--accent) 10%, transparent)" : "transparent",
      color: h ? "var(--ink)" : "var(--ink-dim)",
    },
  };
  return (
    <button {...rest} onMouseEnter={() => setH(true)} onMouseLeave={() => setH(false)}
      style={{ ...base, ...v[variant], ...style }}>
      {children}
    </button>
  );
}

Tifo

Matchday broadsheet on near-black · proven in World Cup 26 · see the whole Tifo set
loading…
Tifo.tsx
"use client";
import React, { useState } from "react";

/* Tifo Button - broadsheet matchday: sharp 3px corners, condensed display caps
   with wide tracking, flat accent strike-fill. No glow anywhere. */

const T = "color 120ms ease, background-color 120ms ease, border-color 120ms ease";
const ACCENT_INK = "#08080a";

export function Button(
  props: React.ButtonHTMLAttributes<HTMLButtonElement> & {
    variant?: "primary" | "secondary" | "ghost";
  }
) {
  const { variant = "secondary", style, onMouseEnter, onMouseLeave, ...rest } = props;
  const [hover, setHover] = useState(false);

  const base: React.CSSProperties = {
    display: "inline-flex", alignItems: "center", gap: 8, borderRadius: 3,
    fontFamily: "var(--font-display)", textTransform: "uppercase",
    letterSpacing: "0.14em", fontWeight: 700, fontSize: 13, lineHeight: 1,
    padding: "9px 16px", cursor: "pointer", transition: T,
  };

  let v: React.CSSProperties;
  let hv: React.CSSProperties = {};
  if (variant === "primary") {
    v = { background: "var(--accent)", border: "1px solid var(--accent)", color: ACCENT_INK };
    hv = hover ? { background: "var(--accent-2)", borderColor: "var(--accent-2)" } : {};
  } else if (variant === "ghost") {
    v = { background: "transparent", border: "1px solid var(--line)", color: "var(--ink-dim)" };
    hv = hover ? { color: "var(--ink)" } : {};
  } else {
    v = { background: "var(--surface-2)", border: "1px solid var(--line)", color: "var(--ink-dim)" };
    hv = hover ? { borderColor: "var(--accent)", color: "var(--ink)" } : {};
  }

  return (
    <button
      {...rest}
      onMouseEnter={(e) => { setHover(true); onMouseEnter?.(e); }}
      onMouseLeave={(e) => { setHover(false); onMouseLeave?.(e); }}
      style={{ ...base, ...v, ...hv, ...style }}
    />
  );
}

Ink

Painted poster plates on deep oil-blue · born in the library · see the whole Ink set
loading…
Ink.tsx
"use client";
import React, { useState } from "react";

/* Ink Button - painted poster plate: condensed display caps, solid accent fill,
   double-plate cel shadow (the accent's own darker step, then near-black). Zero
   blur, zero glow - depth is stacked solid colour. Born in the library. */

const T = "background-color 140ms ease, transform 140ms cubic-bezier(0.22,1,0.36,1), box-shadow 140ms cubic-bezier(0.22,1,0.36,1)";
const PUNCH = "color-mix(in srgb, var(--bg) 40%, #000)";

export function Button(
  props: React.ButtonHTMLAttributes<HTMLButtonElement> & {
    variant?: "primary" | "secondary" | "ghost";
  }
) {
  const { variant = "primary", style, onMouseEnter, onMouseLeave, ...rest } = props;
  const [hover, setHover] = useState(false);
  const shade = "color-mix(in srgb, var(--accent) 62%, #000)";

  const base: React.CSSProperties = {
    display: "inline-flex", alignItems: "center", gap: 8, borderRadius: 2,
    fontFamily: "var(--font-display)", textTransform: "uppercase",
    letterSpacing: "0.06em", fontWeight: 700, fontSize: 13.5, lineHeight: 1,
    padding: "10px 18px", border: "none", cursor: "pointer", transition: T,
    transform: hover ? "translate(-2px, -2px)" : "none",
  };

  let v: React.CSSProperties;
  if (variant === "primary") {
    v = {
      background: hover ? "color-mix(in srgb, var(--accent) 88%, #fff)" : "var(--accent)",
      color: PUNCH,
      boxShadow: hover ? `5px 5px 0 ${shade}, 9px 9px 0 ${PUNCH}` : `3px 3px 0 ${shade}, 6px 6px 0 ${PUNCH}`,
    };
  } else if (variant === "ghost") {
    v = {
      background: "transparent", color: "var(--ink-dim)",
      boxShadow: hover ? `0 3px 0 var(--accent)` : "0 3px 0 var(--line)",
      borderRadius: 0, paddingInline: 6,
    };
  } else {
    v = {
      background: "var(--surface-2)", color: "var(--ink)",
      boxShadow: hover ? `5px 5px 0 ${PUNCH}` : `3px 3px 0 ${PUNCH}`,
    };
  }

  return (
    <button
      {...rest}
      onMouseEnter={(e) => { setHover(true); onMouseEnter?.(e); }}
      onMouseLeave={(e) => { setHover(false); onMouseLeave?.(e); }}
      style={{ ...base, ...v, ...style }}
    />
  );
}

Also in components: Badge · Card · Input