Tarjeta de crédito 3D
Tarjeta skeuomórfica con chip, holograma y relieve que gira para mostrar el reverso con clic o Enter.
Código completo
Es exactamente el archivo que se descarga. Cópialo a tu proyecto y úsalo.
"use client";
import { useState, type CSSProperties } from "react";
/** Tarjeta de crédito skeuomórfica con giro 3D, holograma y relieve estampado. Se voltea con clic o Enter. React + TypeScript, sin dependencias. */
export type TarjetaCreditoProps = {
number?: string;
holder?: string;
expires?: string;
brand?: string;
className?: string;
style?: CSSProperties;
};
const CSS = `
.gctcr-root { box-sizing: border-box; display: block; width: 100%; max-width: 360px; perspective: 1000px; color: #f4f6ff; }
.gctcr-root *, .gctcr-root *::before, .gctcr-root *::after { box-sizing: border-box; }
.gctcr-root button { font: inherit; }
@media (prefers-reduced-motion: reduce) { .gctcr-root *, .gctcr-root *::before, .gctcr-root *::after { transition-duration: .01ms !important; } }
.gctcr-btn { display: block; width: 100%; padding: 0; border: 0; background: none; cursor: pointer; text-align: left; color: inherit; }
.gctcr-btn:focus-visible { outline: 3px solid #fff; outline-offset: 6px; border-radius: 22px; }
.gctcr-card { position: relative; display: block; width: 100%; aspect-ratio: 1.586; transform-style: preserve-3d; transition: transform .8s cubic-bezier(.16, 1, .3, 1); }
.gctcr-btn[aria-pressed="true"] .gctcr-card { transform: rotateY(180deg); }
.gctcr-btn:not([aria-pressed="true"]):hover .gctcr-card { transform: rotateY(-8deg) rotateX(4deg); }
.gctcr-face { position: absolute; inset: 0; display: flex; flex-direction: column; justify-content: space-between; padding: 22px 24px; border-radius: 20px; backface-visibility: hidden; -webkit-backface-visibility: hidden; overflow: hidden; background: radial-gradient(130% 120% at 0% 0%, #5a67d8, #2c2f8f 50%, #14154f); box-shadow: inset 0 1px 0 rgba(255, 255, 255, .4), inset 0 -2px 0 rgba(0, 0, 0, .4), 0 26px 40px -16px rgba(0, 0, 0, .6); }
.gctcr-face::before { content: ""; position: absolute; inset: -50%; background: conic-gradient(from 200deg at 50% 50%, transparent 0 20%, rgba(255, 255, 255, .16) 30%, transparent 40% 70%, rgba(255, 255, 255, .1) 80%, transparent); pointer-events: none; }
.gctcr-back { transform: rotateY(180deg); padding: 0; background: linear-gradient(135deg, #2c2f8f, #14154f); }
.gctcr-row { width: 100%; display: flex; justify-content: space-between; align-items: center; position: relative; }
.gctcr-chip { width: 46px; height: 36px; border-radius: 8px; background: linear-gradient(135deg, #f5de92, #b58b2d 50%, #f5de92); box-shadow: inset 0 0 0 1px rgba(80, 55, 0, .45); }
.gctcr-brand { font: italic 800 22px/1 ui-serif, Georgia, serif; letter-spacing: -.02em; }
.gctcr-num { position: relative; font: 600 20px/1 ui-monospace, "SF Mono", Menlo, monospace; letter-spacing: .1em; text-shadow: 0 -1px 0 rgba(0, 0, 0, .55), 0 1px 0 rgba(255, 255, 255, .18); }
.gctcr-info { position: relative; display: flex; justify-content: space-between; font: 600 12px/1.2 ui-monospace, "SF Mono", Menlo, monospace; letter-spacing: .1em; text-transform: uppercase; text-shadow: 0 -1px 0 rgba(0, 0, 0, .5); }
.gctcr-info small { display: block; margin-bottom: 3px; font-size: 8px; opacity: .65; }
.gctcr-holo { position: absolute; right: 24px; bottom: 54px; width: 38px; height: 28px; border-radius: 6px; background: conic-gradient(from 0deg, #ff8ad4, #8ad8ff, #b6ff8a, #ffe08a, #ff8ad4); opacity: .75; mix-blend-mode: screen; }
.gctcr-stripe { height: 46px; margin-top: 28px; background: #06070f; }
.gctcr-sign { margin: 22px 24px 0; padding: 10px 12px; border-radius: 4px; background: repeating-linear-gradient(135deg, #f4f1e8 0 6px, #e6e2d3 6px 12px); color: #222; font: italic 700 15px/1.2 ui-serif, Georgia, serif; text-align: right; }
.gctcr-note { margin: 16px 24px 0; font-size: 11px; line-height: 1.5; opacity: .7; }`;
export function TarjetaCredito({ number = "4242 8891 0042 7731", holder = "Ana Pérez", expires = "09/29", brand = "banco", className = "", style }: TarjetaCreditoProps) {
const [back, setBack] = useState(false);
return (
<div className={`gctcr-root ${className}`} style={style}>
<style>{CSS}</style>
<button className="gctcr-btn" type="button" aria-pressed={back} aria-label={back ? "Tarjeta, vista trasera. Pulsa para ver el frente" : `Tarjeta ${brand} terminada en ${number.slice(-4)}. Pulsa para ver el reverso`} onClick={() => setBack((value) => !value)}>
<span className="gctcr-card">
<span className="gctcr-face">
<span className="gctcr-row">
<span className="gctcr-chip" />
<span className="gctcr-brand">{brand}</span>
</span>
<span className="gctcr-holo" />
<span className="gctcr-num">{number}</span>
<span className="gctcr-info">
<span>
<small>Titular</small>
{holder}
</span>
<span>
<small>Vence</small>
{expires}
</span>
</span>
</span>
<span className="gctcr-face gctcr-back">
<span className="gctcr-stripe" />
<span className="gctcr-sign">•••</span>
<span className="gctcr-note">Tarjeta de muestra para la demostración. No contiene datos reales.</span>
</span>
</span>
</button>
</div>
);
}
Úsalo en tu proyecto
Instálalo con la CLI de shadcn.
npx shadcn@latest add https://www.gassierconsulting.com/r/tarjeta-creditoEjemplo de uso de Tarjeta de crédito 3D
Después de copiar tarjeta-credito.tsx a tu proyecto, impórtalo y colócalo donde lo necesites.
import { TarjetaCredito } from "./tarjeta-credito";
export default function Ejemplo() {
return <TarjetaCredito number="Ejemplo" />;
}Propiedades de TarjetaCredito
TarjetaCredito acepta 6 propiedades: todas son opcionales y tienen un valor por defecto, así que funciona sin configurar nada.
| Propiedad | Tipo | Descripción |
|---|---|---|
number? | string | Opcional. |
holder? | string | Opcional. |
expires? | string | Opcional. |
brand? | string | Opcional. |
className? | string | Opcional. |
style? | CSSProperties | Opcional. |
Accesibilidad y rendimiento
El archivo tiene 74 líneas (5 KB) y no necesita @keyframes. Esto es lo que hace Tarjeta de crédito 3D por quien lo usa:
- Detecta prefers-reduced-motion y baja o quita el movimiento cuando la persona lo pide.
- Muestra un anillo de foco visible al navegar con teclado (:focus-visible).
- Expone su estado a tecnologías de apoyo con atributos aria-*.
- Es un componente de cliente de Next.js: incluye la directiva "use client".