CardNetworkMark
Visa, Mastercard, Amex, Discover, JCB, UnionPay, Diners. One optical size, a text fallback.
npx shadcn add @lopifi/card-network-markExamples
The same component, case by case. Each stage is the shipped code with the props it shows; switch to Code for the usage.
Unknown network
A network it does not draw prints its name at the same height, never a blank or a wrong mark.
How it behaves
What it renders, what it refuses to render, and why. The same paragraphs as the family spec, so the two can’t disagree.
The network, at a glance, without a request or a broken image.
<CardNetworkMark network="amex" />
<CardNetworkMark network="visa" size={20} variant="mono" />
<CardNetworkMark network="Interac" /> {/* not drawn: prints the name */}
detectCardNetwork("3782 82") // "amex"
detectCardNetwork("3") // null: Amex, Diners Club or JCB
interface CardNetworkMarkProps extends Omit<React.ComponentPropsWithoutRef<"svg">, "children"> {
network: "visa" | "mastercard" | "amex" | "discover" | "jcb" | "unionpay" | "diners" | (string & {});
/** Height in px; the width follows at 5:3. Default 24. */
size?: number;
variant?: "color" | "mono";
/** The accessible name. Defaults to the network's: "American Express". */
label?: string;
}
One artboard. All seven are drawn on the same 40 × 24 box, so a row of them shares a height, a baseline and an optical weight. A logo dropped in at its own aspect ratio makes Mastercard's circles look large beside Visa's letters.
Schematic, not artwork. Each mark is a few shapes and at most one word: Mastercard's
overlapping circles, the Visa letters on a navy field, the Amex box, Discover's disc in place of
the O, the JCB bands, the UnionPay bands, the Diners Club ring. They're recognizable at 16px and
make no attempt to reproduce the network's artwork. A product licensed to show the official mark
passes it where a component takes one (PaymentMethodCard's networkLogo, CardInput's
networkMarks).
mono drops every field and draws the rest in currentColor, so the mark takes the ink of
what it sits on: a card face, a muted row, a dark surface.
A text fallback, never a wrong mark. A network it doesn't draw prints its name in a pill of the same height. A blank space or a generic card icon would leave the reader guessing which card it is.
Detection (detectCardNetwork in lib/card-network.ts) reads the issuer identification
number against the networks' published ranges: Visa 4 · Mastercard 51–55, 2221–2720 · Amex 34,
37 · Discover 6011, 644–649, 65 · JCB 3528–3589 · UnionPay 62 · Diners Club 300–305, 3095, 36,
38–39. A prefix only claims a network when every number it could still become falls inside that
network's range. "3" stays null until the next digit settles it, and "27" stays null until
the fourth, because only 2700–2720 of the 27xx block is Mastercard. The same module carries the
lengths (Amex 15, Diners Club 14, the rest 16), the security-code length (Amex 4, the rest 3) and
the printed grouping (4-6-5, 4-6-4, fours).
Accessibility: role="img" with the network's name. Pass aria-hidden where the name is
already in the surrounding text, such as a field that says "Visa card".
Motion: none. A mark is identity, not feedback.
More in Primitives
See also
Where this component is specified, defined and running.
Elsewhere in the system
The live section CardNetworkMark renders in, the calculators behind its figures, and the ledger payloads that feed it.
Components are copied into your repository and meant to be edited. Rounding policy, fiscal calendar and compliance copy differ per company.
Release notes
Get an email when Primitives changes
Your copy doesn’t update itself when we fix something here.
- One email when a Primitives component needs a migration
- Nothing when nothing changes
Or install it now
npx shadcn add @lopifi/card-network-mark