Dots

Bank Card

A payment card at ISO proportions with 24 plastic designs, an issuer mark, the last four digits and a network logo.

Card ending in 4242
import { BankCard } from "@/components/ui/bank-card"

/** A neutral issuer mark for the demo. Pass your own logo in a product. */

The BankCard component draws a payment card at the ISO 1.586:1 ratio: a plastic design with the issuer mark, the last four digits and the network logo, and nothing else on the face. It comes with 24 built-in designs and takes your own skin with SVG artwork. Use it on card pages, in card lists and in design pickers. To show only the top half of a card under a balance, use CardPeek. To pile several cards, use CardStack.

Installation

pnpm dlx shadcn@latest add @dots/bank-card

Usage

import { BankCard } from "@/components/ui/bank-card"
<BankCard skin="midnight" mark={<IssuerLogo />} network="visa" last4="4242" />

Features

  • 24 built-in plastic designs, or your own skin with SVG artwork
  • Issuer mark slot; the card draws no logo of its own
  • Inline Visa, Mastercard and Mir logos that pick a light or dark print to suit the plastic
  • The last four digits with a full screen-reader phrase
  • Three sizes: the card, a mini thumbnail and a swatch for pickers
  • Scales with its width, so a width class is all you need to resize it
  • A back side for your own content
  • Looks the same in light and dark themes

Sizes

size="default" is the card itself, 340px wide, with the mark, the number and the network logo. mini is a 96px thumbnail for lists and headers with the mark and the logo. swatch is a 96px tile with the mark only, for design pickers.

Card ending in 4242
import { BankCard } from "@/components/ui/bank-card"

/** A neutral issuer mark for the demo. Pass your own logo in a product. */

Width

Every size stops at its natural width and never grows wider than its parent. Set a width class, such as w-[220px] or w-14, to change it: the radius, padding, mark, number and logo scale with the card. Set fluid to fill the parent instead. fluid wins over a width class, so use one or the other.

Card ending in 4242
Travel cardEnding in 4242
import { BankCard } from "@/components/ui/bank-card"

/** A neutral issuer mark for the demo. Pass your own logo in a product. */

In a flex row, align cards with items-start, items-center or items-end. The default stretch makes a card taller than its ratio.

Networks

Set network to "visa", "mastercard" or "mir". The logo is printed white on dark plastics and in colour or black on light ones. Leave network out to show no logo, for example on an offer.

Card ending in 1004
Card ending in 1014
Card ending in 1024
Card ending in 2008
Card ending in 2018
Card ending in 2028
import { BankCard, type CardNetwork } from "@/components/ui/bank-card"

/** A neutral issuer mark for the demo. Pass your own logo in a product. */

Use CardNetworkLogo to show the same logos outside a card. It has no height of its own; size it with a class.

<CardNetworkLogo network="mastercard" className="h-6" />

Designs

Pass a built-in id to skin. cardSkins lists the ids in display order, and getCardSkin(id).name gives the display name.

  • Onyx
  • Eclipse
  • Graphite
  • Carbon
  • Titanium
  • Chrome
  • Pearl
  • Midnight
  • Cobalt
  • Wave
  • Emerald
  • Lime
  • Aurora
  • Sunset
  • Lava
  • Gold
  • Rose
  • Holo
  • Prism
  • Topo
  • Blueprint
  • Dune
  • Ultraviolet
  • Frost
import { BankCard, cardSkins, getCardSkin } from "@/components/ui/bank-card"

/** A neutral issuer mark for the demo. Pass your own logo in a product. */

Custom skin

Pass a CardSkin object to draw your own plastic. background takes any CSS background. art returns SVG children on a 320×202 canvas; prefix every SVG id with the id it receives, so several cards can share a page. Set light for pale plastics, which get dark ink and dark logos, and logos to override a logo print.

Card ending in 5100
import { BankCard, type CardSkin } from "@/components/ui/bank-card"

/** A neutral issuer mark for the demo. Pass your own logo in a product. */
const coral: CardSkin = {
  id: "coral",
  name: "Coral",
  ink: "#fff",
  background: "linear-gradient(150deg, #ff7a59, #8e2d6f)",
  art: (id) => (
    <>
      <radialGradient id={`${id}-glow`}>…</radialGradient>
      <circle cx="250" cy="40" r="120" fill={`url(#${id}-glow)`} />
    </>
  ),
}

Design packs

Ten more series of 20 designs each ship as separate registry items, so an app only carries the ones it uses: card-designs-art, -city, -geo, -grad, -lux, -mono, -nature, -play, -sig and -tech. Each exports one object, such as cardDesignsArt, with an id, a title and its skins, ready for skin and for CardDesignPicker. Import a pack in a client component, because skins carry art functions.

"use client"

import * as React from "react"
pnpm dlx shadcn@latest add @dots/card-designs-art
import { cardDesignsArt } from "@/lib/card-designs-art"
<BankCard skin={cardDesignsArt.skins[0]} network="visa" last4="4242" />

Back side

Set side="back" to draw the plastic without artwork, mark, number or logo. Its children are laid out in a column with the card's padding and follow the skin's ink. Use it for messages such as a card on its way.

Your card is on its wayIt should arrive in 5–7 business days
import { BankCard } from "@/components/ui/bank-card"

export function BankCardBack() {

Accessibility

BankCard is a <div> with no role of its own. Wrap it in a link or a button when it opens something, and name that control.

The number

The masked number is hidden from assistive tech and replaced by a full phrase, "Card ending in 4242" by default. Use numberLabel to change the phrase, for example to translate it.

<BankCard last4="4242" numberLabel={(digits) => `Card ending in ${digits}`} />

Logos and artwork

The network logo is an SVG with role="img" and the network's name, so it is read as "Visa", "Mastercard" or "Mir". The artwork and the grain are hidden from assistive tech. Pass your issuer mark with aria-hidden="true" when it is decorative.

Decorative cards

When a card only repeats what nearby text says, such as a thumbnail next to "Ending in 4242", pass aria-hidden="true" to the card.

API Reference

BankCard

The card. Accepts all <div> props.

PropTypeDefaultDescription
skinCardSkinId | CardSkin"onyx"A built-in design id or your own skin.
size"default" | "mini" | "swatch""default"The card, a thumbnail with mark and logo, or a picker tile with the mark only.
side"front" | "back""front""back" draws the plastic only and lays out children.
markReact.ReactNode-Issuer logo, top start. It fills the mark height; use currentColor to follow the ink.
network"visa" | "mastercard" | "mir"-Payment network logo, bottom end. Not shown on swatches.
last4string-Last four digits, shown on the default size. Leave it out for offers and previews.
numberLabel(digits: string) => string-Screen-reader text for the number. Reads "Card ending in" and the digits by default.
fluidbooleanfalseFill the parent width. Wins over a width class.
childrenReact.ReactNode-Content of the back side.
classNamestring-Additional classes to apply to the root, such as a width.

A network logo as inline SVG. Accepts all <svg> props except children and viewBox.

PropTypeDefaultDescription
network"visa" | "mastercard" | "mir"-Required. Which network.
variant"white" | "black" | "color""color"One-colour print or the network's own colours.
classNamestring-Size it here, e.g. h-6. The logo has no height of its own.

CardSkin

The shape of a custom design.

FieldTypeDescription
idstringRequired. Unique key, also the value a design picker reports.
namestringRequired. Display name, e.g. "Coral".
inkstringRequired. Colour of the mark, the number and back-side content.
backgroundstringRequired. Any CSS background: a colour or stacked gradients.
lightbooleanA pale plastic: dark logos and a lighter edge.
logosPartial<Record<CardNetwork, "white" | "black" | "color">>Logo prints that differ from the ones the tone implies.
sheen"spot" | "full" | "none""spot" (default) keeps a faint glare in the corner, "full" covers the face and "none" leaves the artwork without glare.
art(id: string) => React.ReactNodeSVG children on a 320×202 canvas. Prefix every SVG id with id.

Helpers

ExportTypeDescription
cardSkinsCardSkinId[]Built-in design ids in display order.
getCardSkin(skin: CardSkinId | CardSkin) => CardSkinThe full skin for a built-in id; a skin object is returned as is.
findCardSkin(id: string, list?: ReadonlyArray<CardSkinId | CardSkin>) => CardSkin | undefinedThe skin with this id in a list, all built-ins by default.