PaymentMethodForm
ImplementedAdd-payment-method form with client-side validation for card number, MM/YY expiry, CVC, and name on card.
components/organisms/PaymentMethodForm/PaymentMethodForm.tsxAdd-payment-method form with client-side validation for card number, MM/YY expiry, CVC, and name on card — onSubmit fires only after validation passes; optional onCancel adds a secondary Cancel button.
PaymentMethodForm
Organism — Account & payments family
Self-contained "Add payment method" form: four fields (name, card number with inputMode numeric, MM/YY expiry, 3–4 digit CVC) validated on submit — per-field role="alert" messages wired via aria-invalid + aria-describedby, values preserved across failed submits. onSubmit receives { cardNumber, expiry, cvc, name } only after validation passes; onCancel adds a secondary Cancel button. UI-only: tokenization and persistence belong to the consumer.
Press “Add card” with empty fields to see the validation errors; fill the four fields validly and the payload reaches onSubmit.
Nothing submitted yet.
This component supports light and dark mode.
Usage
PaymentMethodForm owns its field state and validation — hand it onSubmit (the validation gate) and, in modal contexts, onCancel so the flow can back out. Treat the payload as shape-validated, not payment-validated: run your own Luhn check / provider tokenization inside the handler.
import { PaymentMethodForm } from '@epasslive/design-system'
<PaymentMethodForm
onSubmit={(data) => tokenizeCard(data)}
onCancel={() => closeModal()}
/>Validation rules
Built-in, English copy: name non-empty after trim; card number ≥ 13 digits after stripping spaces; expiry matching MM/YY; CVC ≥ 3 characters (maxLength 4). A failed submit renders the error set without clearing entered values, and every message is announced through a role="alert" paragraph linked by aria-describedby. Field and error ids derive from React.useId(), so multiple instances never clash.
Accessibility
Every field pairs a <label htmlFor> with its input (WCAG 1.3.1 / 4.1.2); failed fields set aria-invalid and describe their role="alert" message (WCAG 3.3.1 / 3.3.3) without a focus jump. The numeric fields summon the numeric keypad on touch devices, and the form is named ("Add payment method") via aria-label.
Props
onSubmit*(data: { cardNumber: string; expiry: string; cvc: string; name: string }) => voidCalled on valid submission — validation must pass first.
onCancel() => voidAdds a secondary Cancel button (variant secondary, size sm) left of the submit action.
classNamestringExtra classes on the <form> (fields are already spaced with space-y-4).
Props
PaymentMethodForm
onSubmit(data: { cardNumber: string; expiry: string; cvc: string; name: string }) => void—Called on valid form submission — client-side validation must pass first.
onCancel() => void—Optional secondary Cancel button click handler.
classNamestring—Extra classes on the <form> (fields already spaced with space-y-4).
locale"en" | "fr""en"Localizes all built-in copy (labels, placeholders, error messages, button text). Default 'en' keeps back-compat with the pre-cascade English-only build.
<PaymentMethodForm />