Payment Card
payment-carduiPremium metallic credit-card visual with embossed type, holographic foil, and per-digit typing animation. Auto-detects brand (Visa, Mastercard, Amex, Discover), flips in 3D, and supports opt-in mouse-parallax tilt and shimmer. Pure presentational — pass typed values in via props.
Installation
$pnpm dlx shadcn@latest add https://uipkge.dev/r/react/payment-card.json$npx shadcn@latest add https://uipkge.dev/r/react/payment-card.json$yarn dlx shadcn@latest add https://uipkge.dev/r/react/payment-card.json$bunx shadcn@latest add https://uipkge.dev/r/react/payment-card.jsonNamed registry:
npx shadcn@latest add @uipkge-react/payment-cardInstalls to:components/ui/payment-card/Examples
Loading interactive previews…
Loading interactive previews…
Props
| Name | Type / Values | Default | Required |
|---|---|---|---|
number | string | — | optional |
name | string | — | optional |
expiry | string | — | optional |
cvc | string | — | optional |
brand | CardBrand | 'auto' | — | optional |
flipped | boolean | — | optional |
variant | 'default' | 'compact' | — | optional |
tilt | boolean | — | optional |
shimmer | boolean | — | optional |
flip | boolean | — | optional |
size | 'sm' | 'md' | 'lg' | — | optional |
className | string | — | optional |
Schema
Type aliases from this item's source — use them to shape the data you pass in.
BrandVisualinterface BrandVisual {
cardClass: string
accentGlow: string
foilSheen: string
guillocheColor: string
textColor: string
subtextColor: string
embossStyle: string
chipType: 'gold' | 'silver'
}Used by
Files installed (2)
components/ui/payment-card/payment-card.tsx25.2 kB
'use client' import * as React from 'react' import { cn } from '@/lib/utils' export type CardBrand = 'visa' | 'mastercard' | 'amex' | 'discover' | 'unknown' export interface PaymentCardProps { number?: string name?: string expiry?: string cvc?: string brand?: CardBrand | 'auto' flipped?: boolean variant?: 'default' | 'compact' tilt?: boolean shimmer?: boolean flip?: boolean size?: 'sm' | 'md' | 'lg' className?: string } function detectBrand(raw: string): CardBrand { const n = raw.replace(/\D/g, '') if (!n) return 'unknown' if (/^4/.test(n)) return 'visa' if (/^(5[1-5]|2[2-7])/.test(n)) return 'mastercard' if (/^3[47]/.test(n)) return 'amex' if (/^(6011|65|64[4-9])/.test(n)) return 'discover' return 'unknown' } function formatMasked(raw: string, brand: CardBrand): string { const digits = raw.replace(/\D/g, '').slice(0, brand === 'amex' ? 15 : 16) const groups = brand === 'amex' ? [4, 6, 5] : [4, 4, 4, 4] const total = groups.reduce((a, b) => a + b, 0) const padded = (digits + '••••••••••••••••').slice(0, total) let i = 0 return groups .map((g) => { const slice = padded.slice(i, i + g) i += g return slice }) .join(' ') } interface BrandVisual { cardClass: string accentGlow: string foilSheen: string guillocheColor: string textColor: string subtextColor: string embossStyle: string chipType: 'gold' | 'silver' } const BRAND_VISUALS: Record<CardBrand, BrandVisual> = { visa: { cardClass: 'bg-[radial-gradient(ellipse_at_top_right,#1e3a8a_0%,#0f2252_45%,#08122c_85%,#040a18_100%)] text-white shadow-[0_22px_45px_-12px_rgba(15,34,82,0.65),0_8px_16px_-8px_rgba(0,0,0,0.5)]', accentGlow: 'from-blue-400/20 via-indigo-500/10 to-transparent', foilSheen: 'from-white/20 via-blue-200/5 to-transparent', guillocheColor: 'rgba(96, 165, 250, 0.12)', textColor: 'text-white', subtextColor: 'text-blue-200/60', embossStyle: 'text-white drop-shadow-[0_1px_1px_rgba(0,0,0,0.8)]', chipType: 'gold', }, mastercard: { cardClass: 'bg-[radial-gradient(ellipse_at_top_right,#2a0808_0%,#180608_35%,#0f0506_70%,#09090b_100%)] text-white shadow-[0_22px_45px_-12px_rgba(220,38,38,0.35),0_8px_16px_-8px_rgba(0,0,0,0.6)]', accentGlow: 'from-red-500/25 via-amber-500/15 to-transparent', foilSheen: 'from-white/20 via-orange-300/10 to-transparent', guillocheColor: 'rgba(239, 68, 68, 0.1)', textColor: 'text-white', subtextColor: 'text-zinc-400', embossStyle: 'text-zinc-100 drop-shadow-[0_1px_2px_rgba(0,0,0,0.9)]', chipType: 'gold', }, amex: { cardClass: 'bg-[radial-gradient(ellipse_at_top_right,#1e293b_0%,#0f172a_40%,#090d16_80%,#020617_100%)] text-slate-100 shadow-[0_22px_45px_-12px_rgba(15,23,42,0.7),0_8px_16px_-8px_rgba(0,0,0,0.6)]', accentGlow: 'from-slate-300/20 via-teal-500/10 to-transparent', foilSheen: 'from-white/25 via-cyan-100/10 to-transparent', guillocheColor: 'rgba(148, 163, 184, 0.12)', textColor: 'text-slate-100', subtextColor: 'text-slate-400', embossStyle: 'text-slate-100 drop-shadow-[0_1px_2px_rgba(0,0,0,0.9)]', chipType: 'silver', }, discover: { cardClass: 'bg-[radial-gradient(ellipse_at_top_right,#431407_0%,#270d04_45%,#1c0903_80%,#0c0401_100%)] text-white shadow-[0_22px_45px_-12px_rgba(194,65,12,0.45),0_8px_16px_-8px_rgba(0,0,0,0.6)]', accentGlow: 'from-orange-400/25 via-amber-600/15 to-transparent', foilSheen: 'from-white/20 via-amber-200/10 to-transparent', guillocheColor: 'rgba(251, 146, 60, 0.12)', textColor: 'text-white', subtextColor: 'text-amber-200/60', embossStyle: 'text-white drop-shadow-[0_1px_2px_rgba(0,0,0,0.9)]', chipType: 'gold', }, unknown: { cardClass: 'bg-[radial-gradient(ellipse_at_top_right,#27272a_0%,#18181b_40%,#09090b_85%,#000000_100%)] text-white shadow-[0_22px_45px_-12px_rgba(0,0,0,0.7),0_8px_16px_-8px_rgba(0,0,0,0.5)]', accentGlow: 'from-zinc-400/15 via-zinc-600/10 to-transparent', foilSheen: 'from-white/18 via-zinc-300/5 to-transparent', guillocheColor: 'rgba(255, 255, 255, 0.06)', textColor: 'text-white', subtextColor: 'text-zinc-400', embossStyle: 'text-zinc-100 drop-shadow-[0_1px_2px_rgba(0,0,0,0.9)]', chipType: 'silver', }, } export const PaymentCard = React.forwardRef<HTMLDivElement, PaymentCardProps>( ( { number = '', name = '', expiry = '', cvc = '', brand = 'auto', flipped = false, variant = 'default', tilt = false, shimmer = false, flip = true, size = 'md', className, }, ref, ) => { const cardElRef = React.useRef<HTMLDivElement | null>(null) const [tiltState, setTiltState] = React.useState({ x: 0, y: 0, active: false }) const detectedBrand: CardBrand = React.useMemo(() => { if (brand && brand !== 'auto') return brand return detectBrand(number) }, [brand, number]) const theme = BRAND_VISUALS[detectedBrand] const displayNumber = React.useMemo(() => formatMasked(number, detectedBrand), [number, detectedBrand]) const displayName = React.useMemo(() => (name.trim() || 'CARDHOLDER NAME').toUpperCase(), [name]) const displayExpiry = React.useMemo(() => { const raw = expiry.replace(/\D/g, '').slice(0, 4) if (!raw) return 'MM/YY' if (raw.length <= 2) return raw + '/YY' return `${raw.slice(0, 2)}/${raw.slice(2, 4)}` }, [expiry]) const displayCvc = React.useMemo(() => { const max = detectedBrand === 'amex' ? 4 : 3 const digits = cvc.replace(/\D/g, '').slice(0, max) return digits || '•••' }, [cvc, detectedBrand]) const displayChars = React.useMemo(() => displayNumber.split(''), [displayNumber]) // Sizing const sizeClass = React.useMemo(() => { if (variant === 'compact') return 'w-[120px]' switch (size) { case 'sm': return 'w-[280px]' case 'lg': return 'w-[420px]' case 'md': default: return 'w-[360px]' } }, [variant, size]) // Tilt handler const onMouseMove = (e: React.MouseEvent<HTMLDivElement>) => { if (!tilt || !cardElRef.current) return const rect = cardElRef.current.getBoundingClientRect() const x = e.clientX - rect.left const y = e.clientY - rect.top const px = (x / rect.width - 0.5) * 2 const py = (y / rect.height - 0.5) * 2 setTiltState({ x: -py * 10, y: px * 12, active: true }) } const onMouseLeave = () => { if (!tilt) return setTiltState({ x: 0, y: 0, active: false }) } const innerTransform = React.useMemo(() => { const flipDeg = flipped ? 180 : 0 if (tilt && tiltState.active) { return `perspective(1200px) rotateX(${tiltState.x}deg) rotateY(${tiltState.y + flipDeg}deg) scale3d(1.02, 1.02, 1.02)` } return `perspective(1200px) rotateY(${flipDeg}deg)` }, [tilt, tiltState, flipped]) return ( <div ref={(node) => { cardElRef.current = node if (typeof ref === 'function') ref(node) else if (ref) (ref as React.MutableRefObject<HTMLDivElement | null>).current = node }} data-uipkge data-slot="payment-card" role="img" aria-label={`${detectedBrand === 'unknown' ? 'Card' : detectedBrand} ending ${displayNumber.replace(/[•\s]/g, '').slice(-4) || '••••'}, ${displayName}, expires ${displayExpiry}`} className={cn('group relative inline-block select-none [perspective:1200px]', sizeClass, className)} onMouseMove={onMouseMove} onMouseLeave={onMouseLeave} > <div className={cn( 'relative aspect-[85.6/53.98] w-full transition-transform [transform-style:preserve-3d]', flip ? 'duration-[650ms] ease-[cubic-bezier(0.22,1,0.36,1)]' : 'duration-300', )} style={{ transform: innerTransform }} > {/* ================================= FRONT FACE ================================= */} <div className={cn( 'pay-card-face absolute inset-0 overflow-hidden rounded-[16px] border border-white/15 [backface-visibility:hidden]', theme.cardClass, )} > {/* Fine Guilloché & Security Geometric Wave Pattern */} <svg className="pointer-events-none absolute inset-0 size-full opacity-60 mix-blend-screen" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 360 227" fill="none" aria-hidden="true" > <g stroke={theme.guillocheColor} strokeWidth="0.75" strokeOpacity="0.7"> <path d="M-40 40 C 60 180, 180 -40, 400 120" /> <path d="M-40 55 C 60 195, 180 -25, 400 135" /> <path d="M-40 70 C 60 210, 180 -10, 400 150" /> <path d="M-40 85 C 60 225, 180 5, 400 165" /> <path d="M-40 100 C 60 240, 180 20, 400 180" /> <path d="M-40 115 C 60 255, 180 35, 400 195" /> <circle cx="280" cy="80" r="90" strokeWidth="0.5" strokeDasharray="2 3" /> <circle cx="280" cy="80" r="60" strokeWidth="0.5" strokeDasharray="1 2" /> </g> </svg> {/* Brushed Metallic Sheen & Specular Lighting */} <div className="pointer-events-none absolute inset-0 bg-gradient-to-tr from-transparent via-white/[0.07] to-transparent opacity-80" /> <div className={cn( 'pointer-events-none absolute -inset-y-8 -left-1/3 w-1/2 rotate-12 bg-gradient-to-r opacity-70', theme.foilSheen, )} /> {/* Ambient Corner Highlights */} <div className={cn( 'pointer-events-none absolute -top-12 -right-12 h-44 w-44 rounded-full bg-gradient-to-br blur-2xl', theme.accentGlow, )} /> <div className="pointer-events-none absolute -bottom-10 -left-10 h-36 w-36 rounded-full bg-black/40 blur-2xl" /> {/* Outer Bevel Perimeter Ring */} <div className="pointer-events-none absolute inset-0 rounded-[16px] shadow-[inset_0_1px_1px_rgba(255,255,255,0.35),inset_0_-1px_1px_rgba(0,0,0,0.5)]" /> {/* Shimmer sweep (opt-in) */} {shimmer && ( <div className="pointer-events-none absolute -inset-x-full inset-y-0 bg-gradient-to-r from-transparent via-white/25 to-transparent" style={{ animation: 'payment-card-shimmer 2.5s linear infinite' }} /> )} {/* Content Structure */} <div className={cn('absolute inset-0 flex flex-col justify-between', variant === 'compact' ? 'p-2' : 'p-5')} > {/* TOP ROW: Bank Watermark / Card Tier & Brand Logo */} <div className="flex items-center justify-between"> {/* Left: Card Tier / Bank label */} <div className="flex items-center gap-1.5"> {variant !== 'compact' ? ( <span className="font-mono text-xs font-semibold tracking-[0.25em] text-white/70 uppercase"> {detectedBrand === 'amex' ? 'PLATINUM' : detectedBrand === 'mastercard' ? 'WORLD ELITE' : 'SIGNATURE'} </span> ) : ( <span className="font-mono text-xs font-bold tracking-widest text-white/70 uppercase">CARD</span> )} </div> {/* Right: Authentic Brand Logo */} <div className="flex items-center justify-end"> {/* VISA */} {detectedBrand === 'visa' && ( <svg className={variant === 'compact' ? 'h-3 w-auto' : 'h-6 w-auto'} viewBox="0 0 78 24" fill="none" xmlns="http://www.w3.org/2000/svg" aria-label="Visa" > <path d="M29.5 23.2H23.9L27.4 1.8H33L29.5 23.2ZM52.4 2.3C51.3 1.9 49.5 1.5 47.3 1.5C41.8 1.5 37.9 4.4 37.8 8.6C37.7 11.7 40.5 13.4 42.6 14.4C44.8 15.5 45.5 16.2 45.5 17.1C45.5 18.6 43.7 19.2 42.1 19.2C39.8 19.2 38.5 18.9 36.8 18.1L36 17.7L35.1 23C36.6 23.7 39.2 24.2 41.8 24.2C47.7 24.2 51.5 21.3 51.6 16.9C51.7 13.4 49.6 11.7 47 10.4C45.2 9.5 44.1 8.9 44.1 8C44.1 7.2 45 6.4 46.8 6.4C48.3 6.4 49.6 6.7 50.8 7.2L51.3 7.5L52.4 2.3ZM67.5 1.8H63.2C61.8 1.8 60.8 2.2 60.2 3.6L51.4 23.2H57.3L58.5 19.9H65.7L66.4 23.2H71.6L67.5 1.8ZM60.1 15.5C60.6 14.2 62.5 8.9 62.5 8.9C62.5 8.9 63 7.6 63.3 6.7L63.8 8.7C63.8 8.7 64.9 14.1 65.2 15.5H60.1ZM18.7 1.8L13.2 16.4L12.6 13.4C11.6 10 8.7 6.3 5.4 4.5L10.3 23.2H16.3L25.1 1.8H18.7ZM8.3 1.8H0.2L0 2.3C6.3 3.9 10.4 7.7 12.1 12.4L10.4 3.7C10.1 2.4 9.3 1.9 8.3 1.8Z" fill="white" /> <path d="M12.1 12.4L10.4 3.7C10.1 2.4 9.3 1.9 8.3 1.8H0.2L0 2.3C6.3 3.9 10.4 7.7 12.1 12.4Z" fill="#F9A01B" /> </svg> )} {/* MASTERCARD */} {detectedBrand === 'mastercard' && ( <div className="flex items-center gap-1.5"> <svg className={variant === 'compact' ? 'h-3.5 w-auto' : 'h-7 w-auto'} viewBox="0 0 48 30" fill="none" xmlns="http://www.w3.org/2000/svg" aria-label="Mastercard" > <circle cx="15" cy="15" r="15" fill="#EB001B" /> <circle cx="33" cy="15" r="15" fill="#F79E1B" fillOpacity="0.92" /> <path d="M24 4.5C27.5 7.1 29.8 11.2 29.8 16C29.8 20.8 27.5 24.9 24 27.5C20.5 24.9 18.2 20.8 18.2 16C18.2 11.2 20.5 7.1 24 4.5Z" fill="#FF5F00" /> </svg> {variant !== 'compact' && ( <span className="font-mono text-xs font-bold tracking-tight text-white lowercase" style={{ letterSpacing: '-0.05em' }} > mastercard </span> )} </div> )} {/* AMEX */} {detectedBrand === 'amex' && ( <div className={cn( 'flex items-center justify-center rounded-sm bg-[#006fcf] font-sans font-bold tracking-tighter text-white shadow-xs', variant === 'compact' ? 'px-1 py-0.5 text-xs' : 'px-2 py-1 text-xs', )} > AMEX </div> )} {/* DISCOVER */} {detectedBrand === 'discover' && ( <div className={cn( 'flex items-center gap-0.5 font-bold tracking-wider text-white', variant === 'compact' ? 'text-xs' : 'text-xs', )} > <span>DISC</span> <span className={cn( 'inline-block rounded-full bg-gradient-to-br from-amber-400 to-orange-600 shadow-xs', variant === 'compact' ? 'size-2' : 'size-3.5', )} /> <span>VER</span> </div> )} {/* UNKNOWN */} {detectedBrand === 'unknown' && ( <div className="flex items-center gap-1 opacity-80"> <div className="size-2 rounded-full bg-white/60" /> <div className="size-2 rounded-full bg-white/30" /> <span className={cn( 'font-mono font-bold tracking-widest text-white/80 uppercase', variant === 'compact' ? 'text-xs' : 'text-xs', )} > PREMIUM </span> </div> )} </div> </div> {/* MIDDLE ROW: EMV Chip + Contactless Symbol */} <div className="flex items-center justify-between"> <div className="flex items-center gap-3"> {/* Ultra-Realistic Metallic EMV Chip */} <div className={cn( 'relative overflow-hidden rounded-[5px] border border-amber-950/40 shadow-[0_2px_5px_rgba(0,0,0,0.5),inset_0_1px_0_rgba(255,255,255,0.6)]', theme.chipType === 'silver' ? 'bg-gradient-to-br from-slate-200 via-slate-300 to-slate-400' : 'bg-gradient-to-br from-[#ffe082] via-[#ffb300] to-[#ff8f00]', variant === 'compact' ? 'h-3.5 w-5' : 'h-8 w-11', )} > {/* Authentic Chip Circuit Etching Lines */} <div className="absolute inset-[2px] rounded-[3px] border border-black/25" /> <div className="absolute inset-x-0 top-1/2 h-px -translate-y-1/2 bg-black/30" /> <div className="absolute inset-y-0 left-1/3 w-px bg-black/30" /> <div className="absolute inset-y-0 right-1/3 w-px bg-black/30" /> <div className="absolute top-1/4 right-1/3 left-1/3 h-1/2 rounded-[2px] border border-black/25 bg-black/10" /> {/* Metallic Glint Reflection */} <div className="pointer-events-none absolute inset-0 bg-gradient-to-tr from-transparent via-white/40 to-transparent" /> </div> {/* Contactless NFC Radio Waves */} {variant !== 'compact' && ( <svg viewBox="0 0 24 24" className="h-5 w-auto text-white/70 drop-shadow-sm" fill="none" stroke="currentColor" strokeWidth="1.75" strokeLinecap="round" aria-hidden="true" > <path d="M6.5 8a6 6 0 0 1 0 8" /> <path d="M10 6a9.5 9.5 0 0 1 0 12" /> <path d="M13.5 4a13 13 0 0 1 0 16" /> </svg> )} </div> {/* Holographic Security Stamp */} {variant !== 'compact' && <div className="pay-card-holo h-7 w-9 rounded-[4px] opacity-75 shadow-xs" />} </div> {/* CARD NUMBER (Authentic Embossed Raised Digits) */} <div className={cn( 'flex flex-nowrap items-center font-mono font-bold tracking-[0.18em] tabular-nums', theme.embossStyle, variant === 'compact' ? 'my-0.5 text-xs' : 'my-1 text-base sm:text-lg', )} > <span className="sr-only">{displayNumber}</span> {displayChars.map((ch, i) => ( <span key={`${i}-${ch}`} className={cn( 'inline-block origin-bottom tabular-nums transition-transform', ch === '•' && 'text-[0.85em] opacity-50', )} aria-hidden="true" > {ch === ' ' ? '\u00A0' : ch} </span> ))} </div> {/* BOTTOM ROW: Cardholder Name + Expiry Date */} <div className="flex items-end justify-between gap-3"> {/* Cardholder Name */} <div className="min-w-0 flex-1"> {variant !== 'compact' && ( <div className={cn('text-xs font-semibold tracking-[0.2em] uppercase', theme.subtextColor)}> CARDHOLDER NAME </div> )} <div className={cn( 'truncate font-semibold tracking-wider uppercase', theme.embossStyle, variant === 'compact' ? 'text-xs' : 'text-xs', )} > {displayName} </div> </div> {/* Expiry Date */} <div className="shrink-0 text-right"> {variant !== 'compact' && ( <div className={cn( 'flex items-center justify-end gap-1 text-xs font-semibold tracking-wider uppercase', theme.subtextColor, )} > <span className="text-[6px] leading-tight"> GOOD <br /> THRU </span> <span>MONTH/YEAR</span> </div> )} <div className={cn( 'font-mono font-semibold tracking-wider whitespace-nowrap', theme.embossStyle, variant === 'compact' ? 'text-xs' : 'text-xs', )} > {displayExpiry} </div> </div> </div> </div> </div> {/* ================================= BACK FACE ================================= */} <div className={cn( 'pay-card-face absolute inset-0 [transform:rotateY(180deg)] overflow-hidden rounded-[16px] border border-white/15 [backface-visibility:hidden]', theme.cardClass, )} > {/* Specular Bevel Perimeter */} <div className="pointer-events-none absolute inset-0 rounded-[16px] shadow-[inset_0_1px_1px_rgba(255,255,255,0.35),inset_0_-1px_1px_rgba(0,0,0,0.5)]" /> {/* Full-Width Deep Matte Magnetic Stripe */} <div className={cn( 'w-full bg-gradient-to-b from-neutral-950 via-black to-neutral-900 shadow-[inset_0_1px_0_rgba(255,255,255,0.1),inset_0_-1px_0_rgba(0,0,0,0.8)]', variant === 'compact' ? 'mt-2 h-4' : 'mt-4 h-10', )} /> <div className={cn('relative flex flex-col justify-between', variant === 'compact' ? 'p-2' : 'p-4')}> {/* Signature Panel + CVV Code */} <div className={cn('flex items-stretch gap-2', variant === 'compact' ? 'mt-1' : 'mt-2')}> {/* White Security Hatched Signature Strip */} <div className={cn( 'relative flex-1 overflow-hidden rounded-[3px] border border-slate-300/80 bg-white/95 px-2 py-1', variant === 'compact' ? 'h-4' : 'h-8', )} style={{ backgroundImage: 'repeating-linear-gradient(-45deg, rgba(0, 0, 0, 0.05) 0px, rgba(0, 0, 0, 0.05) 2px, transparent 2px, transparent 6px)', }} > {variant !== 'compact' && ( <div className="font-mono text-xs font-semibold tracking-wider text-slate-400 uppercase"> AUTHORIZED SIGNATURE </div> )} </div> {/* Printed CVV Code Box */} <div className={cn( 'flex flex-col items-center justify-center rounded-[3px] border border-slate-300 bg-white font-mono font-bold text-slate-950 shadow-inner', variant === 'compact' ? 'px-1 text-xs' : 'px-3 text-xs', )} > {variant !== 'compact' && ( <span className="text-[6px] font-bold tracking-widest text-slate-400 uppercase">CVV</span> )} <span className="leading-none tracking-widest italic">{displayCvc}</span> </div> </div> {/* Microtext Disclaimer & Regulatory Compliance Marks */} {variant !== 'compact' && ( <div className="mt-3 space-y-1.5"> <p className="text-[7.5px] leading-snug text-white/50"> This card is property of the issuing bank and must be returned upon request. Use is subject to the cardholder agreement. </p> <div className="flex items-center justify-between border-t border-white/10 pt-2 text-xs font-medium text-white/60"> <span>24/7 Support: 1-800-555-0199</span> <span className="font-mono font-bold tracking-wider text-white/75">CIRRUS · PLUS · STAR</span> </div> </div> )} </div> </div> </div> </div> ) }, ) PaymentCard.displayName = 'PaymentCard'components/ui/payment-card/index.ts0.1 kB
export { PaymentCard, type PaymentCardProps } from './payment-card'
Raw manifest:https://uipkge.dev/r/react/payment-card.json