The Kit/Components/Card

Card

Content panels with kicker, title, body and footer slots: edge-lit instrument panel, hairline broadsheet frame, offset poster plate.

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 Card - rounded instrument panel: accent edge-light, lit kicker dot,
   lift + accent border on hover. Colour from theme vars. */

export function Card({ kicker, title, sub, footer, children, style }: {
  kicker?: React.ReactNode; title?: React.ReactNode; sub?: React.ReactNode; footer?: React.ReactNode; children?: React.ReactNode; style?: React.CSSProperties;
}) {
  const [h, setH] = React.useState(false);
  return (
    <div
      onMouseEnter={() => setH(true)} onMouseLeave={() => setH(false)}
      style={{
        position: "relative", borderRadius: 16, overflow: "hidden",
        background: "var(--surface)", color: "var(--ink)", fontFamily: "var(--font-ui)",
        border: `1px solid ${h ? "color-mix(in srgb, var(--accent) 45%, var(--line))" : "var(--line)"}`,
        transform: h ? "translateY(-3px)" : "translateY(0)",
        boxShadow: h ? "0 14px 34px -16px color-mix(in srgb, var(--accent) 40%, transparent), 0 10px 28px -18px rgba(0,0,0,0.7)" : "none",
        transition: "transform .18s ease, border-color .18s ease, box-shadow .18s ease",
        ...style,
      }}>
      <div style={{
        position: "absolute", top: 0, left: 0, right: 0, height: 2,
        background: "linear-gradient(90deg, var(--accent), transparent 70%)",
      }} />
      {(kicker || title || sub) && (
        <div style={{ padding: "16px 18px 12px" }}>
          {kicker && (
            <div style={{ display: "flex", alignItems: "center", gap: 7, marginBottom: 8 }}>
              <span style={{
                width: 6, height: 6, borderRadius: 999, background: "var(--accent)",
                boxShadow: "0 0 7px var(--accent)", flex: "0 0 auto",
              }} />
              <span style={{
                fontFamily: "var(--font-mono)", fontSize: 10, textTransform: "uppercase",
                letterSpacing: "1.4px", color: "var(--ink-faint)",
              }}>{kicker}</span>
            </div>
          )}
          {title && <div style={{ fontFamily: "var(--font-display)", fontWeight: 700, fontSize: 17, letterSpacing: "-0.01em" }}>{title}</div>}
          {sub && <div style={{ color: "var(--ink-dim)", fontSize: 13, marginTop: 3 }}>{sub}</div>}
        </div>
      )}
      {children && <div style={{ padding: "0 18px 16px", color: "var(--ink-dim)", fontSize: 13.5, lineHeight: 1.55 }}>{children}</div>}
      {footer && <div style={{ padding: "12px 18px", borderTop: "1px solid var(--line)", display: "flex", alignItems: "center", gap: 10, fontSize: 13 }}>{footer}</div>}
    </div>
  );
}

Tifo

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

/* Tifo Card - broadsheet panel: hairline frame, header rule, condensed caps title,
   mono kicker in the accent. Flat; the type does the work. */

export function Card(props: {
  kicker?: React.ReactNode;
  title?: React.ReactNode;
  sub?: React.ReactNode;
  footer?: React.ReactNode;
  children?: React.ReactNode;
  style?: React.CSSProperties;
}) {
  const { kicker, title, sub, footer, children, style } = props;
  const hasHeader = kicker !== undefined || title !== undefined || sub !== undefined;

  return (
    <div style={{
      borderRadius: 3, background: "var(--surface)", border: "1px solid var(--line)",
      overflow: "hidden", fontFamily: "var(--font-ui)", color: "var(--ink-dim)",
      ...style,
    }}>
      {hasHeader ? (
        <div style={{ display: "flex", alignItems: "center", gap: 10, padding: "10px 14px", borderBottom: "1px solid var(--line)" }}>
          {kicker !== undefined ? (
            <span style={{ fontFamily: "var(--font-mono)", fontWeight: 800, fontSize: 12, lineHeight: 1, color: "var(--accent)" }}>{kicker}</span>
          ) : null}
          {title !== undefined ? (
            <h3 style={{
              margin: 0, fontFamily: "var(--font-display)", fontWeight: 800, fontSize: 16,
              lineHeight: 1.1, textTransform: "uppercase", letterSpacing: "0.16em", color: "var(--ink)",
            }}>{title}</h3>
          ) : null}
          {sub !== undefined ? (
            <span style={{ marginLeft: "auto", fontFamily: "var(--font-mono)", fontSize: 10.5, textTransform: "uppercase", letterSpacing: "0.04em", color: "var(--ink-faint)" }}>{sub}</span>
          ) : null}
        </div>
      ) : null}
      {children !== undefined ? <div style={{ padding: 14, fontSize: 13.5, lineHeight: 1.6 }}>{children}</div> : null}
      {footer !== undefined ? <div style={{ padding: "10px 14px", borderTop: "1px solid var(--line)" }}>{footer}</div> : null}
    </div>
  );
}

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 Card - a poster plate: solid surface offset by its own darker step and a
   near-black plate (stacked solid colour = the shading). Condensed caps header
   over a hard rule. Hover lifts the plate off the stack. */

export function Card(props: {
  kicker?: React.ReactNode;
  title?: React.ReactNode;
  sub?: React.ReactNode;
  footer?: React.ReactNode;
  children?: React.ReactNode;
  style?: React.CSSProperties;
}) {
  const { kicker, title, sub, footer, children, style } = props;
  const [h, setH] = useState(false);
  const punch = "color-mix(in srgb, var(--bg) 40%, #000)";
  const hasHeader = kicker !== undefined || title !== undefined || sub !== undefined;

  return (
    <div
      onMouseEnter={() => setH(true)} onMouseLeave={() => setH(false)}
      style={{
        borderRadius: 2, background: "var(--surface)", color: "var(--ink-dim)",
        fontFamily: "var(--font-ui)",
        boxShadow: h
          ? `6px 6px 0 color-mix(in srgb, var(--accent) 45%, var(--surface-2)), 12px 12px 0 ${punch}`
          : `4px 4px 0 color-mix(in srgb, var(--accent) 30%, var(--surface-2)), 8px 8px 0 ${punch}`,
        transform: h ? "translate(-2px, -2px)" : "none",
        transition: "transform 160ms cubic-bezier(0.22,1,0.36,1), box-shadow 160ms cubic-bezier(0.22,1,0.36,1)",
        ...style,
      }}>
      {hasHeader ? (
        <div style={{ display: "flex", alignItems: "baseline", gap: 10, padding: "13px 16px 11px", borderBottom: `3px solid ${punch}` }}>
          {kicker !== undefined ? (
            <span style={{ width: 9, height: 9, background: "var(--accent)", alignSelf: "center", boxShadow: `2px 2px 0 color-mix(in srgb, var(--accent) 55%, #000)` }} aria-hidden />
          ) : null}
          {title !== undefined ? (
            <h3 style={{
              margin: 0, fontFamily: "var(--font-display)", fontWeight: 700, fontSize: 16,
              lineHeight: 1.05, textTransform: "uppercase", letterSpacing: "0.04em", color: "var(--ink)",
            }}>{title}</h3>
          ) : null}
          {sub !== undefined ? (
            <span style={{ marginLeft: "auto", fontFamily: "var(--font-display)", fontWeight: 700, fontSize: 11, textTransform: "uppercase", letterSpacing: "0.06em", color: "var(--ink-faint)" }}>{sub}</span>
          ) : null}
        </div>
      ) : null}
      {children !== undefined ? <div style={{ padding: "13px 16px", fontSize: 13.5, lineHeight: 1.6 }}>{children}</div> : null}
      {footer !== undefined ? <div style={{ padding: "11px 16px", borderTop: "1px solid var(--line)", display: "flex", alignItems: "center", gap: 10 }}>{footer}</div> : null}
    </div>
  );
}

Also in components: Badge · Button · Input