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.
Purpose
Credit Card Field is a compound credit card input field pattern for card number, expiry, and CVC in one visually unified shell. It is a payment form card details 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 a payment form’s joined card-details input. 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.
What validation does Credit Card Field perform?
Consumers can supply an error string to show invalid chrome and message text. Skrewww does not run Luhn checks or card-network validation. This remains a UI/input pattern for card details — not a payment processor.
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."
/>
);
}