Forms
Credit Card Field
Credit Card Field is a compound UI control for card number, expiry, and CVC in one shell — visual pattern only, not a payment processor or PCI vault.
State (Default/Focused/Error/Disabled) — 4 variants
betaReact AvailableFigma AvailableDocs Partial
- React last updated
- 2026-09-14
- Documentation last updated
- 2026-09-14
- Accessibility target
- WCAG 2.2 AA (target)
- Version
- 0.1.0-beta
Known open questions
- Figma default TEXT shows masked demo digits (••••) — React does not mask PANs; apps must not treat UI masking as security.
- No Size axis in Figma — shell matches Text Input md height.
- Production card capture should prefer hosted/tokenized provider fields; this component is the visual pattern only.
Live preview
Compound shell: generic card icon + number + expiry + CVC. Values stay digit-only; spaces/slash are display-only.
Interactive
Digits: — / — / —
Default with synthetic filled value
Error
Disabled
Read-only
Purpose
Credit Card Field is a compound UI control for card number, expiry, and CVC in one visually unified shell. It is a visual/input pattern only — not a payment processor, tokenizer, or PCI vault.
Anatomy
CreditCardField = fieldset/legend + shared shell (generic CreditCard icon + number input + divider + expiry input + divider + CVC input) + optional supporting/error text.
Variants and states
default · focused · error · disabled
When to use
When documenting or prototyping the joined card-details pattern. For production card capture, prefer a payment provider’s hosted/tokenized fields.
When not to use
When using Stripe Elements / Adyen / similar hosted card elements. Do not treat this React control as sufficient for PCI-sensitive production capture.
Accessibility
fieldset + legend for the group; each segment is a real text input with its own accessible name (number/expiry/CVC). Focus chrome is shell-level (:focus-within). Generic CreditCard icon is decorative (aria-hidden).
Keyboard behavior
Standard text editing in each segment. Tab moves between number, expiry, and CVC. Shell focus-within shows the Focused chrome.
Common mistakes
Treating this as one text input. Treating display spaces/slash as stored value. Assuming brand detection or payment authorization. Logging or persisting raw card digits.
Properties
Figma: State + Card Number / Expiry / CVC text. React: label, value/defaultValue/onValueChange ({number,expiry,cvc} digit-only), segment labels/placeholders, disabled, readOnly, required, error, supportingText.
Is this a payment integration?
No. It does not tokenize, authorize, store, or transmit card data. Prefer Stripe Elements / equivalent hosted fields for PCI-sensitive capture.
Does it detect Visa/Mastercard?
No. Figma uses a generic Icon/CreditCard deliberately — network logos are not reproduced.
Tokens used
component/radius/controlsemantic/border/defaultsemantic/focus-ringsemantic/action/dangercolor/neutral/200
Known limitation
Figma demo TEXT may show masked bullets — React does not mask PANs. No brand logos. No Luhn/network validation. /r deferred to CE-3. This component does not claim PCI compliance.
Component API
| Prop | Type | Default | Description |
|---|---|---|---|
| label | string | — | Visible fieldset legend for the compound control. |
| value | { number: string; expiry: string; cvc: string } | — | Controlled digit-only values (no spaces/slash). Display formatting is presentation-only. |
| defaultValue | { number: string; expiry: string; cvc: string } | — | Uncontrolled initial digit-only values. |
| onValueChange | (value: { number; expiry; cvc }) => void | — | Fires with digit-only values after edits/paste. |
| numberLabel | string | "Card number" | Accessible name for the number segment. |
| expiryLabel | string | "Expiry" | Accessible name for the expiry segment. |
| cvcLabel | string | "CVC" | Accessible name for the CVC segment. |
| disabled | boolean | false | Disables all segments and dims the shell. |
| readOnly | boolean | false | Read-only segments; shell remains interactive for focus. |
| required | boolean | false | Marks the group and each segment required. |
| error | string | — | Error message; sets invalid chrome on the shared shell. |
| supportingText | string | — | Help text when no error is present. |
React example
Copy React example
import { useState } from "react";
import { CreditCardField } from "@/components/ui/CreditCardField";
export function Example() {
const [value, setValue] = useState({ number: "", expiry: "", cvc: "" });
return (
<CreditCardField
label="Card details"
value={value}
onValueChange={setValue}
supportingText="UI pattern only — use a payment provider for real card capture."
/>
);
}