This component no longer exists. It was in ns-ui’s manifest when we first indexed it and is not there now — the registry served its inventory on 2026-08-07 and this item was not on it. The install command below will fail. It is kept here because a tutorial somewhere still tells people to run it.
Card Number Emboss
ns-ui/card-number-embossRemovedComponent
A card-number input rendered as an embossing machine — typed digits raise as bevel-shadowed metal, a stamping-head caret dips on every keystroke, and a brand watermark fades in once enough digits exist.
Live preview
live · rendered by the registry
Rendered by ns-ui on their own page — this is the component running, not a screenshot of it.Install it
npx shadcn@latest add https://design.helpmarq.com/r/card-number-emboss.jsonSource
1"use client";23import { useCallback, useEffect, useId, useMemo, useRef, useState, type ChangeEvent } from "react";45// ---------------------------------------------------------------------------6// EmbossPlate — a card-number input rendered as an embossing machine, not a7// flat text field. Typed digits RAISE as embossed metal (a dual text-shadow8// bevel, light top-left / dark bottom-right), grouped 4-4-4-4, with a small9// stamping-head caret that dips on every keystroke. A brand watermark10// (detected from the IIN prefix, or a generic wordmark) fades in once 4+11// digits exist. Expiry and CVC share the same emboss treatment.12//13// Real input semantics: one native <input> per field, transparent and14// overlaid exactly on top of its decorative display (never sr-only-tiny —15// the visible plate area IS the click/tap target), so typing, autofill,16// paste, and screen-reader behavior all come from genuine form controls.17// The formatted display underneath is aria-hidden and purely presentational.18// Because the real inputs are transparent, focus is shown on the DISPLAY19// sibling via a CSS focus-visible + adjacent-sibling rule, not on the20// (invisible) input itself.21// ---------------------------------------------------------------------------2223export interface EmbossPlateProps {24 className?: string;25}2627const GROUP_SIZES = [4, 4, 4, 4] as const;2829function luhnValid(digits: string): boolean {30 if (digits.length === 0) return false;31 let sum = 0;32 let alt = false;33 for (let i = digits.length - 1; i >= 0; i--) {34 let n = Number(digits[i]);35 if (alt) {36 n *= 2;37 if (n > 9) n -= 9;38 }39 sum += n;40 alt = !alt;41 }42 return sum % 10 === 0;43}4445function detectBrand(digits: string): string {46 if (digits.startsWith("4")) return "VISA";47 if (/^5[1-5]/.test(digits)) return "MASTERCARD";48 if (/^3[47]/.test(digits)) return "AMEX";49 return "BANK";50}5152function formatGroups(digits: string): string[] {53 const groups: string[] = [];54 let i = 0;55 for (const size of GROUP_SIZES) {56 groups.push(digits.slice(i, i + size));57 i += size;58 }59 return groups;60}6162// Monochrome film-grain overlay via feTurbulence — never a CSS gradient63// function, so it can't read as a decorative color wash.64const NOISE_BG = `url("data:image/svg+xml,${encodeURIComponent(65// … truncated
