import type { ReactNode } from "react";
const variants = {
ink: "bg-(--tui-credit-card-ink-bg) text-(--tui-credit-card-ink-fg) border-transparent",
brand: "bg-(--tui-credit-card-brand-bg) text-(--tui-credit-card-brand-fg) border-transparent",
surface: "bg-(--tui-credit-card-surface-bg) text-(--tui-credit-card-surface-fg) border-(--tui-credit-card-surface-border)",
};
export interface CreditCardProps {
variant?: keyof typeof variants;
/** The issuer or the product, top left. */
title?: ReactNode;
/** The last four digits. The rest are never shown. */
last4: string;
name: ReactNode;
/** When it runs out, e.g. "06/28". */
expiry: ReactNode;
/** The network's mark, bottom right: a logo or its name. */
network?: ReactNode;
className?: string;
}
/** A payment card, drawn. For showing which card is on file, not for typing one in. */
export function CreditCard({ variant = "ink", title, last4, name, expiry, network, className }: CreditCardProps) {
return (
<div
data-slot="credit-card"
role="img"
aria-label={`Card ending in ${last4}`}
className={[
"relative flex aspect-[1.586] w-(--tui-credit-card-width) max-w-full flex-col justify-between overflow-hidden rounded-(--tui-credit-card-radius) border-solid border-(length:--tui-credit-card-border-width) p-(--tui-credit-card-padding) font-(family-name:--tui-font) shadow-(--tui-credit-card-shadow)",
// A sheen across the top corner, in the card's own text colour so it suits every variant.
"before:pointer-events-none before:absolute before:inset-0 before:bg-[linear-gradient(135deg,currentColor,transparent_55%)] before:opacity-(--tui-credit-card-sheen)",
variants[variant],
className,
]
.filter(Boolean)
.join(" ")}
>
<div className="relative flex items-start justify-between gap-3">
<span className="text-(length:--tui-credit-card-font-size) leading-none font-semibold">{title}</span>
<svg aria-hidden viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" className="size-[1.4em] opacity-80">
<path d="M5 5.500a4 4 0 0 1 0 5M8 4a6.500 6.500 0 0 1 0 8M11 2.500a9 9 0 0 1 0 11" />
</svg>
</div>
<div className="relative flex flex-col gap-[0.9em] text-(length:--tui-credit-card-font-size)">
<span aria-hidden className="h-[1.9em] w-[2.6em] rounded-[0.35em] bg-(--tui-credit-card-chip) opacity-90" />
<span className="font-(family-name:--tui-credit-card-mono) text-[1.15em] leading-none tracking-[0.14em] tabular-nums">•••• •••• •••• {last4}</span>
<div className="flex items-end justify-between gap-3 leading-none">
<span className="flex flex-col gap-[0.5em]">
<span className="text-[0.72em] tracking-[0.08em] uppercase opacity-65">Card holder</span>
<span className="font-medium">{name}</span>
</span>
<span className="flex flex-col gap-[0.5em]">
<span className="text-[0.72em] tracking-[0.08em] uppercase opacity-65">Expires</span>
<span className="font-medium tabular-nums">{expiry}</span>
</span>
{network && <span className="text-[1.1em] font-bold tracking-tight italic">{network}</span>}
</div>
</div>
</div>
);
}:root {
color-scheme: light;
--tui-bg: #ffffff;
--tui-fg: #0a0a0a;
--tui-muted: #f5f5f5;
--tui-muted-fg: #737373;
--tui-border: #e5e5e5;
--tui-primary: #171717;
--tui-primary-fg: #fafafa;
--tui-ring: #a3a3a3;
--tui-success: #16a34a;
--tui-warning: #d97706;
--tui-danger: #dc2626;
--tui-radius: 8px;
--tui-border-width: 1px;
--tui-space: 4px;
--tui-shadow: none;
--tui-font: ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
--tui-text: 14px;
--tui-duration: 150ms;
/* Credit card */
--tui-credit-card-width: 300px;
--tui-credit-card-padding: calc(var(--tui-space) * 5);
--tui-credit-card-radius: calc(var(--tui-radius) * 2);
--tui-credit-card-border-width: var(--tui-border-width);
--tui-credit-card-shadow: 0 12px 32px rgb(0 0 0 / 0.14);
--tui-credit-card-sheen: 0.12;
--tui-credit-card-font-size: 13px;
--tui-credit-card-mono: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
--tui-credit-card-chip: color-mix(in oklab, var(--tui-warning) 55%, var(--tui-bg));
--tui-credit-card-ink-bg: var(--tui-fg);
--tui-credit-card-ink-fg: var(--tui-bg);
--tui-credit-card-brand-bg: var(--tui-primary);
--tui-credit-card-brand-fg: var(--tui-primary-fg);
--tui-credit-card-surface-bg: var(--tui-muted);
--tui-credit-card-surface-fg: var(--tui-fg);
--tui-credit-card-surface-border: var(--tui-border);
}
.dark,
[data-theme="dark"] {
color-scheme: dark;
--tui-bg: #0a0a0a;
--tui-fg: #fafafa;
--tui-muted: #1c1c1c;
--tui-muted-fg: #a3a3a3;
--tui-border: #2a2a2a;
--tui-primary: #fafafa;
--tui-primary-fg: #171717;
--tui-ring: #737373;
--tui-success: #22c55e;
--tui-warning: #f59e0b;
--tui-danger: #ef4444;
}Needs Tailwind CSS v4. Import the stylesheet once, after Tailwind.