EmpireUI
Get Pro
← Blog7 min read#glassmorphism#bank-card#react-component

Glassmorphism Bank Card: Credit Card Component in React

Build a glassmorphism bank card component in React with Tailwind CSS. Frosted-glass credit card UI with chip, card number, and hover animations — ready to drop in.

Frosted glass credit card component floating over a purple gradient background

Why a Glassmorphism Credit Card Actually Makes Sense

Honestly, the bank card is one of those UI patterns where glassmorphism earns its keep — not just as a visual gimmick but as a genuinely appropriate metaphor. Physical bank cards are glossy, reflective, premium-feeling. A frosted glass treatment mimics that tactile quality on screen better than a flat or skeuomorphic card ever could.

You see this pattern everywhere now: fintech dashboards, crypto wallets, digital banking apps. Companies like Revolut and Curve have leaned into it hard. And when you look at what glassmorphism actually is at a technical level — blur, transparency, a subtle border — it maps almost perfectly to the aesthetic language banks have been using in their marketing for years.

The good news is it's not that hard to build. With Tailwind CSS and a few lines of inline style for the blur, you can have a fully animated, responsive credit card component in under 100 lines of JSX. Let's build it.

The Core CSS Behind the Frosted Glass Effect

Before touching React, you need to understand the three properties doing all the heavy lifting. First: backdrop-filter: blur(12px). That's the frosted glass. Without it you just have a semi-transparent rectangle — not the same thing at all. Second: a background of rgba(255,255,255,0.12) gives you the translucency without washing everything out. Third: a 1px border at rgba(255,255,255,0.25) catches the light and defines the card edge.

Tailwind v4.0.2 ships backdrop-blur-md which maps to backdrop-filter: blur(12px) — that's your sweet spot for cards. Go lower and the blur isn't convincing. Go higher (blur-xl at 24px) and details behind the card become unreadable. The 12px value works because it's blurry enough to feel frosted but you still get colour hints from whatever's underneath.

One thing a lot of people miss: backdrop-filter only works if the element behind it has something to blur. If your card sits on a white or solid background, the effect is invisible. You need a gradient, an image, or a particles background behind the card for it to read correctly in your UI.

Building the React Credit Card Component

Here's the full component. It's typed, self-contained, and takes props for card number, cardholder name, expiry, and an optional gradient for the background layer.

import React from 'react';

interface BankCardProps {
  cardNumber?: string;
  cardHolder?: string;
  expiry?: string;
  gradient?: string;
}

const formatCardNumber = (num: string) =>
  num.replace(/\s/g, '').replace(/(\d{4})/g, '$1 ').trim();

export function GlassBankCard({
  cardNumber = '4532 1234 5678 9012',
  cardHolder = 'JANE DOE',
  expiry = '12/28',
  gradient = 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
}: BankCardProps) {
  const formatted = formatCardNumber(cardNumber.replace(/\s/g, ''));
  const masked =
    formatted.split(' ').map((g, i) => (i < 3 ? '••••' : g)).join(' ');

  return (
    <div
      className="relative w-[360px] h-[220px] rounded-2xl overflow-hidden
                 cursor-pointer select-none
                 transition-transform duration-300 hover:-translate-y-1
                 hover:shadow-2xl"
      style={{ background: gradient }}
    >
      {/* Glass overlay */}
      <div
        className="absolute inset-0 rounded-2xl"
        style={{
          background: 'rgba(255,255,255,0.12)',
          backdropFilter: 'blur(12px)',
          WebkitBackdropFilter: 'blur(12px)',
          border: '1px solid rgba(255,255,255,0.25)',
        }}
      />

      {/* Sheen strip */}
      <div
        className="absolute top-0 left-0 right-0 h-[60px] rounded-t-2xl"
        style={{
          background:
            'linear-gradient(180deg, rgba(255,255,255,0.18) 0%, rgba(255,255,255,0) 100%)',
        }}
      />

      {/* Content */}
      <div className="relative z-10 flex flex-col justify-between h-full p-6">
        {/* Top row: network logo + chip */}
        <div className="flex items-center justify-between">
          <div
            className="w-10 h-8 rounded-md"
            style={{
              background:
                'linear-gradient(135deg, #f6d365 0%, #fda085 100%)',
              boxShadow: '0 2px 8px rgba(0,0,0,0.3)',
            }}
          />
          <span
            className="text-white/80 text-xs font-semibold tracking-widest"
          >
            EMPIRE PAY
          </span>
        </div>

        {/* Card number */}
        <div className="text-white text-xl font-mono tracking-widest">
          {masked}
        </div>

        {/* Bottom row */}
        <div className="flex items-end justify-between">
          <div>
            <p className="text-white/50 text-[10px] uppercase tracking-wider mb-0.5">
              Card Holder
            </p>
            <p className="text-white text-sm font-medium tracking-wide">
              {cardHolder}
            </p>
          </div>
          <div className="text-right">
            <p className="text-white/50 text-[10px] uppercase tracking-wider mb-0.5">
              Expires
            </p>
            <p className="text-white text-sm font-medium">{expiry}</p>
          </div>
          {/* Visa-style circles */}
          <div className="flex">
            <div className="w-8 h-8 rounded-full bg-red-500/70" />
            <div className="w-8 h-8 rounded-full bg-yellow-400/70 -ml-3" />
          </div>
        </div>
      </div>
    </div>
  );
}

A few decisions worth explaining. The gradient lives on the outer div — not the glass overlay. This is intentional: the glass layer sits on top of the gradient, giving you the frosted look while preserving the colour depth underneath. If you applied the gradient and blur to the same element, you'd lose the effect entirely.

The WebkitBackdropFilter duplicate is not optional. Safari still needs it as of late 2026, and fintech products can't afford to ignore iOS Safari users.

Adding a 3D Flip Animation for the Card Back

A static card is fine. A flipping card is better. You can add CSS 3D perspective with a wrapper, then flip on hover or on a useState toggle. Here's the wrapper CSS you'd add — either as a Tailwind @layer component or inline:

.card-scene {
  perspective: 1000px;
  width: 360px;
  height: 220px;
}

.card-inner {
  position: relative;
  width: 100%;
  height: 100%;
  transition: transform 0.6s cubic-bezier(0.4, 0, 0.2, 1);
  transform-style: preserve-3d;
}

.card-scene:hover .card-inner,
.card-inner.flipped {
  transform: rotateY(180deg);
}

.card-front,
.card-back {
  position: absolute;
  inset: 0;
  backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
}

.card-back {
  transform: rotateY(180deg);
}

The back face shows the magnetic stripe, CVV field, and a blacked-out signature strip. Apply the same glass treatment to the back — same rgba(255,255,255,0.12) background, same 12px blur. It should look like two sides of one physical card, not two separate components.

One gotcha: backface-visibility: hidden and backdrop-filter can conflict in some Chromium versions. If the blur disappears on the back face, add transform: translateZ(0) to force GPU compositing on that element.

Theming: Dark Mode, Light Mode, and Custom Gradients

The glassmorphism bank card is one of those components where dark mode is the default, not the afterthought. Light mode cards with a white glass overlay over a light background read as nearly invisible — the contrast just isn't there. You either need a dark or saturated gradient behind the card, or you invert the glass colour to a dark tint.

For light-mode contexts, swap rgba(255,255,255,0.12) to rgba(0,0,0,0.08) and flip the border to rgba(0,0,0,0.12). It reads as smoked glass rather than frosted glass — still in the same family. You can wire this up with a theme toggle in React and a CSS variable swap so both modes share the same component.

For custom gradients, expose a gradient prop as shown in the component above. Some palettes that work well with the glass overlay: 135deg, #0f0c29, #302b63, #24243e (deep purple), 135deg, #1a1a2e, #16213e, #0f3460 (midnight blue), and 135deg, #11998e, #38ef7d (teal/green for crypto products). You can also reference the best free glassmorphism components article for more pre-built gradient presets.

Accessibility and Security Considerations

There's a real tension here. Glass effects look great but low-contrast white-on-translucent text can fail WCAG AA at 4.5:1 contrast. The card number in text-white over a purple gradient typically passes — around 5.8:1 — but check every colour combination with a real contrast checker, not your eyes.

Why are we masking the card number by default? Because this component will often end up near actual card data in fintech dashboards. Masking to •••• •••• •••• 9012 (last 4 visible) is the PCI-DSS standard and should be the default prop behaviour. Let the consumer explicitly opt into showing the full number by passing an unmask boolean.

Tab order matters too. If the card has any interactive elements — a copy button, a toggle to reveal the full number — make sure they're reachable via keyboard. The card itself is div-based, so wrap interactive children in <button> elements, not <div onClick> handlers. Screen readers need real semantics.

Glassmorphism vs Other Card Styles: When to Use Each

You don't have to use glassmorphism for every card component. It works when: you have a rich background to blur against, you want a premium/financial aesthetic, and the content on the card is high-contrast enough to read through the translucency. If any of those aren't true, consider alternatives.

Neumorphism bank cards are a common alternative — soft shadows on a monochrome background, extruded plastic look. If you're curious about the tradeoffs, glassmorphism vs neumorphism covers the comparison in depth. Neobrutalism is another direction: flat colours, thick borders, no subtlety. Completely different vibe but it works for challenger banks targeting Gen Z. Claymorphism — the puffy, 3D inflated look — is harder to pull off on a rectangle like a card but you see it in some crypto NFT wallet UIs.

For corporate banking dashboards, glassmorphism is almost always the right call. The luxury associations are exactly what those products want. For budget trackers or expense management tools, a flatter, more utilitarian card might actually serve users better — glass effects can feel incongruous when someone's staring at a $47 overdraft.

Dropping the Card Into a Real Dashboard Layout

The component is 360×220px by default — that's a real bank card aspect ratio (85.6mm × 53.98mm, scaled). In a dashboard grid you'll usually have it in a col-span-2 card section alongside account balance, recent transactions, and quick-send buttons.

One layout pattern that works well: put the card on the left third of the grid, stack balance + last-4-transactions on the right two-thirds. The glass card becomes an anchor element — users intuitively associate it with their account the same way they associate a physical card with their wallet. It's doing visual work that a bare account-number display can't.

If you're working with Tailwind CSS modules in a larger design system, you'll want to extract the glass variables — blur amount, background opacity, border opacity — into CSS custom properties rather than hardcoding them inline. That way your design token system controls the glass intensity and you're not hunting through JSX to tweak rgba values.

FAQ

Why doesn't my backdrop-filter blur work in Safari?

Safari requires the -webkit- prefix. Set both backdropFilter: 'blur(12px)' and WebkitBackdropFilter: 'blur(12px)' on the same element. Also confirm you're not applying backdrop-filter to an element that has overflow: hidden on a parent — that can silently break it in older Safari versions.

How do I make the glassmorphism card responsive for mobile?

Swap the fixed 360px width for w-full max-w-[360px]. The height needs to stay proportional (85.6:53.98 ratio ≈ 1.586:1), so use a padding-bottom trick: padding-bottom: 63% on a relative-positioned wrapper, then absolute-position the card content inside. This preserves the physical card proportions at any width.

Is it safe to display real card numbers in this component?

The component should never receive or render a full 16-digit PAN (Primary Account Number) unless you're a PCI-DSS Level 1 certified environment. In most dashboard UIs you'll receive a masked number from your API — something like ****1234 — and display that. The formatCardNumber utility in the example handles formatting but you should mask at the data layer, not the UI layer.

Can I use this component without Tailwind CSS?

Yes. The glass effect itself — the important part — uses inline styles (backdropFilter, background, border). The layout classes (flex, rounded-2xl, p-6) can be swapped for plain CSS or CSS Modules. Tailwind handles convenience but doesn't carry the glassmorphism logic.

The glass effect disappears when I put the card on a white background. Why?

Backdrop-filter blurs whatever is visually behind the element. On a white background, there's nothing to blur — or rather, blurring white gives you white. You need colour, texture, or imagery behind the card. Add a gradient div behind it, use a hero image, or place the card over a colourful section of your layout.

How do I animate the card number reveal (unmask on click)?

Use a useState boolean and conditionally render the masked vs. full number string. Wrap the reveal in a transition-all duration-300 on a span and use blur-smblur-0 classes toggling to make the digits appear to come into focus — it's a nice UX detail that reinforces the security framing.

Free components in 40 styles
React & Tailwind, copy-paste ready.
Browse →

Read next

Glassmorphism Profile Card: User Avatar ComponentGlassmorphism Activity Feed: Social Timeline ComponentGlassmorphism vs Solid Design: Which Converts Better in 2027Component State Design: Default, Hover, Active, Disabled, Error