EmpireUI
Get Pro
← Blog7 min read#glassmorphism#invoice-ui#finance-app

Glassmorphism Invoice UI: Finance App Component Design

Build a glassmorphism invoice UI component for finance apps — frosted glass cards, backdrop blur, Tailwind v4, and real code you can drop into your React project.

Frosted glass invoice card UI on a gradient purple background showing line items and totals

Why Glassmorphism Works for Finance UIs

Honestly, finance apps are one of the few contexts where glassmorphism actually earns its place — not just as decoration, but as a way to layer information hierarchy visually. When you've got a dashboard packed with invoices, totals, due dates, and client names, the frosted glass treatment helps the eye separate card surfaces from the ambient background without relying on hard borders.

The effect originated from Apple's macOS Big Sur design language, but it's since become a legit pattern for SaaS billing UIs. If you've been following the what is glassmorphism primer, you already know the three pillars: background blur, semi-transparent fill, and a subtle border at around 1px using rgba(255,255,255,0.2). Invoice cards hit all three naturally.

The trick is restraint. Don't apply the effect to every element on the page. Reserve it for the card surface itself — the parent wrapper that contains line items, amounts, and status badges. Everything inside stays flat and readable. That contrast between the blurred glass container and the crisp text inside it is what makes the hierarchy click.

Core CSS Properties for the Glass Invoice Card

Before we touch React at all, let's nail the CSS. The foundation is backdrop-filter: blur(16px) paired with a background of rgba(255,255,255,0.1). That blur radius is a good starting point — anything below 8px looks murky, anything above 24px starts eating into performance on mobile. Sixteen sits in a comfortable middle ground.

You also need a border to sell the glass edge. A 1px solid rgba(255,255,255,0.2) on all sides, combined with a box-shadow of 0 8px 32px rgba(0,0,0,0.2), gives you the slight depth that distinguishes the card from the background gradient. Don't skip the shadow — without it the card reads as flat.

.glass-invoice-card {
  background: rgba(255, 255, 255, 0.1);
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
  border: 1px solid rgba(255, 255, 255, 0.2);
  border-radius: 16px;
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.2);
  padding: 24px;
}

One thing that trips people up: backdrop-filter only works when the element has a transparent or semi-transparent background. If you accidentally set background: white, the blur disappears entirely because there's nothing to show through. Keep that background alpha below 0.25 for a genuine glass feel, though you can go up to 0.35 for better text legibility on light gradient backgrounds.

Building the React Invoice Component with Tailwind v4

With Tailwind v4.0.2 you get backdrop-blur-* utilities out of the box, which maps to backdrop-filter: blur() with a set of preset values. The backdrop-blur-xl class gives you 24px of blur — that's slightly more than the sweet spot, so I usually override it with an arbitrary value like backdrop-blur-[16px]. Tailwind v4 handles arbitrary values cleanly without needing to add them to a safelist.

import React from 'react';

interface LineItem {
  description: string;
  qty: number;
  unitPrice: number;
}

interface GlassInvoiceProps {
  invoiceNumber: string;
  clientName: string;
  dueDate: string;
  items: LineItem[];
  status: 'paid' | 'pending' | 'overdue';
}

const statusStyles = {
  paid: 'bg-emerald-400/20 text-emerald-300 border border-emerald-400/30',
  pending: 'bg-amber-400/20 text-amber-300 border border-amber-400/30',
  overdue: 'bg-rose-400/20 text-rose-300 border border-rose-400/30',
};

export function GlassInvoiceCard({
  invoiceNumber,
  clientName,
  dueDate,
  items,
  status,
}: GlassInvoiceProps) {
  const subtotal = items.reduce((sum, i) => sum + i.qty * i.unitPrice, 0);
  const tax = subtotal * 0.2;
  const total = subtotal + tax;

  return (
    <div
      className={
        'relative rounded-2xl p-6 ' +
        'bg-white/10 backdrop-blur-[16px] ' +
        'border border-white/20 ' +
        'shadow-[0_8px_32px_rgba(0,0,0,0.2)]'
      }
    >
      {/* Header */}
      <div className="flex items-start justify-between mb-6">
        <div>
          <p className="text-white/50 text-xs uppercase tracking-widest mb-1">Invoice</p>
          <h2 className="text-white font-semibold text-lg">{invoiceNumber}</h2>
          <p className="text-white/70 text-sm mt-1">{clientName}</p>
        </div>
        <span
          className={`text-xs font-medium px-3 py-1 rounded-full ${statusStyles[status]}`}
        >
          {status.charAt(0).toUpperCase() + status.slice(1)}
        </span>
      </div>

      {/* Line items */}
      <div className="space-y-3 mb-6">
        {items.map((item, idx) => (
          <div key={idx} className="flex justify-between text-sm">
            <span className="text-white/80">{item.description}</span>
            <span className="text-white font-medium">
              ${(item.qty * item.unitPrice).toFixed(2)}
            </span>
          </div>
        ))}
      </div>

      {/* Divider */}
      <div className="border-t border-white/10 mb-4" />

      {/* Totals */}
      <div className="space-y-2 text-sm">
        <div className="flex justify-between text-white/60">
          <span>Subtotal</span>
          <span>${subtotal.toFixed(2)}</span>
        </div>
        <div className="flex justify-between text-white/60">
          <span>Tax (20%)</span>
          <span>${tax.toFixed(2)}</span>
        </div>
        <div className="flex justify-between text-white font-semibold text-base mt-2">
          <span>Total</span>
          <span>${total.toFixed(2)}</span>
        </div>
      </div>

      {/* Footer */}
      <p className="text-white/40 text-xs mt-6">Due: {dueDate}</p>
    </div>
  );
}

The status badge uses Tailwind's opacity modifier syntax — bg-emerald-400/20 sets the background to emerald-400 at 20% opacity. That's the same glass-within-glass pattern applied to a smaller element. It reads clearly on the card surface without fighting for attention.

Background Setup: Making the Blur Actually Visible

Here's the thing: the blur effect is invisible if you put a glass card on a flat white or dark background. The backdrop-filter composites whatever is behind the element — on a solid color, that's just the same solid color with a slight fog. You need a rich, multi-color gradient or an image behind the card.

For invoice pages, a two-stop diagonal gradient works well. Something like background: linear-gradient(135deg, #1a1a2e 0%, #16213e 50%, #0f3460 100%) gives you depth without being distracting. Drop a few blurred color blobs (absolutely positioned divs with a large border-radius and filter: blur(80px)) in the background and the glass card comes alive.

If you want the full ambient light treatment, check out the particles background React approach — you can run it behind glass cards at reduced opacity and it reads really well in finance dashboards. Alternatively, a static gradient is lighter on performance and perfectly sufficient for production invoice views.

One performance note: backdrop-filter triggers GPU compositing. On a page with 20+ invoice cards visible simultaneously, that can cause paint issues on lower-end devices. Benchmark it. If you're rendering a long list, consider applying the glass style only to the focused/hovered card and keeping the rest as flat cards with a matching color palette.

Status Badges and Color Coding in Glass Context

Finance components live and die by their status indicators. Paid, pending, overdue — users need to scan a list and catch the red ones instantly. The challenge with glassmorphism is that saturated solid colors can look jarring against a frosted surface. The solution is semi-transparent colored badges that inherit some of the glass language.

Using the /20 opacity modifier on the background and a /30 opacity border gives you colored badges that look native to the glass surface. The text color stays at full saturation — text-emerald-300 rather than text-emerald-300/60 — so it remains readable. That combination of a faint fill with vivid text is the pattern that works.

What about dark mode? The same rgba values hold up surprisingly well. The gradient background shifts darker, the card fill stays at rgba(255,255,255,0.1), and the badge colors are already translucent so they adapt. You won't need separate dark-mode overrides for the glass card itself, though you might want to bump up text opacity slightly — text-white/90 instead of text-white/80 in dark contexts.

Glassmorphism Invoice vs Neumorphism: Picking the Right Style

If you've read the glassmorphism vs neumorphism comparison, you know these two approaches diverge sharply in finance contexts. Neumorphism uses the same-color emboss/deboss trick — it requires a fixed background color and doesn't translate to gradient or image backgrounds. That's a hard constraint for dashboards where you want visual depth.

Glassmorphism wins for invoice cards specifically because it naturally stacks. You can have a glass page container, glass section panels, and glass individual invoice cards — each layer reads as a distinct depth plane. Neumorphism collapses when you try to nest it; two neumorphic elements side by side on a neumorphic background just looks like a flat gray mass.

Is neumorphism ever the right call for finance? Sometimes — for isolated input fields or toggle switches where the tactile metaphor makes sense. But for cards that need to sit above a rich background and communicate hierarchy at a glance, glassmorphism is the more practical choice. Use what the design actually needs, not what looks cool in a Dribbble shot.

Accessibility and Readability Considerations

Semi-transparent backgrounds are a real accessibility concern. The WCAG 2.1 contrast ratio requirement is 4.5:1 for normal text. When your card fill is rgba(255,255,255,0.1) over a dark gradient, the effective background behind your text might be around #1e2a45. White text on that clears the ratio comfortably. But if someone has a light-colored gradient background, the same setup might fail.

Test your contrast ratios with actual computed values, not eyeballed estimates. The theme toggle React pattern is useful here — if you're toggling between a light and dark gradient background, make sure the card text contrast holds in both modes. You might need to flip from text-white to text-gray-900 when the background is light.

Font weight matters more in glass contexts than in flat UIs. At font-weight: 400 over a blurred background, text can feel floaty and hard to read. Bumping line items to font-medium (500) and totals to font-semibold (600) adds the visual anchor that makes the numbers scannable. Small investment, big legibility return.

Also: don't forget prefers-reduced-motion. The backdrop-filter blur itself is static, so it's fine. But if you're adding hover animations on the card — scale, translate, shadow transitions — wrap them in a @media (prefers-reduced-motion: no-preference) block. Finance apps often run in enterprise environments where users have that setting on.

Integrating with Empire UI's Free Glassmorphism Components

Empire UI ships a set of free glassmorphism components that you can use as the foundation for invoice UIs without writing every glass style from scratch. The base card component already handles backdrop-blur, border, and shadow tokens — you extend it with invoice-specific slots for line items and totals.

The component tokens use CSS custom properties, so you can override the blur radius and background opacity at the theme level without touching the component source. Set --glass-blur: 16px and --glass-bg: rgba(255,255,255,0.12) in your CSS root and every glass component inherits those values. That's the approach that scales when you've got 30 different glass cards across a finance app.

For routing between invoice pages, pairing glass cards with Tailwind vs CSS modules is worth thinking through. The glass styles are naturally inline-first — they don't need complex selector nesting — so Tailwind utility classes tend to be a cleaner fit than CSS modules for this particular pattern. But if your team already has a CSS modules setup, the custom properties approach above works just as well.

The Empire UI invoice card ships with three states out of the box: default, hover (adds a 0 12px 40px rgba(0,0,0,0.3) shadow and a slight translateY(-2px)), and a print-safe fallback that drops the backdrop blur and applies a flat #f8fafc background. That last one matters — finance apps get printed, and backdrop-filter doesn't render in most print stylesheets.

FAQ

Does backdrop-filter work in all browsers for production invoice apps?

As of late 2026, backdrop-filter has over 96% global browser support including Chrome, Firefox, Safari, and Edge. The -webkit-backdrop-filter prefix is still needed for older iOS Safari (pre-15.4). For the small percentage of unsupported browsers, add a fallback background like rgba(30,42,69,0.9) so the card remains readable without the blur effect.

What blur radius should I use for a glass invoice card — 8px, 16px, or 24px?

16px is the most reliable starting point. At 8px the frosted effect is too subtle and looks like a rendering artifact. At 24px you start seeing performance hits on mobile and the blur can wash out fine text details. Use backdrop-blur-[16px] in Tailwind v4 arbitrary value syntax. If you're targeting a premium desktop SaaS context, 20px is fine.

How do I make glass invoice cards work in a print stylesheet?

Add a @media print block that sets background to a solid light color (e.g., #f8fafc), removes backdrop-filter, and switches text colors to dark values. Print rendering engines ignore backdrop-filter entirely, so without a fallback your printed invoice will show semi-transparent backgrounds over a white page — which just looks like very light gray boxes.

Can I nest glass cards inside a glass container without the effect collapsing?

Yes, but each nested glass element composites against the content behind it in the stacking context, not against its parent element. So a glass card inside a glass panel will blur through both layers. Reduce the inner card's blur radius to 8px and keep the outer container at 16px to maintain visual depth. Don't set identical blur values on nested elements.

What background setup works best behind glassmorphism invoice cards?

A multi-stop diagonal gradient with at least two distinct hues is the minimum. Linear gradients like linear-gradient(135deg, #1a1a2e, #0f3460) work well. Adding 2-3 absolutely positioned blur blobs (large radii colored divs with filter: blur(80px) at low opacity) makes the glass depth much more convincing. Avoid solid single-color backgrounds — backdrop-filter has nothing interesting to blur.

How do I handle WCAG contrast ratios with semi-transparent glass backgrounds?

Calculate your effective background color by compositing the card background (e.g., rgba(255,255,255,0.1)) over the gradient behind it. Use a tool like the Colour Contrast Analyser with the actual pixel color you see on screen, not the CSS value. White text over a computed #1e2a45 background clears 4.5:1 easily. If your gradient uses lighter mid-tones, bump font weight to semibold and increase text opacity to /95.

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

Read next

Glassmorphism File Manager: Cloud Storage UI DesignGlassmorphism Avatar Group: User List with Stacked DesignGlassmorphism vs Solid Design: Which Converts Better in 2027Component State Design: Default, Hover, Active, Disabled, Error