Skip to main content
Mounts inside Payments. Create it to get a handle, then mount its elements on that handle. Call destroy() to remove the sub-controller and free its slot. Create it again to get a fresh handle.
Exclusive. CardFields is an alternative to PaymentElement or CardElement in this Payments handle. Mount one at a time. Destroy it before mounting another.

Preview

A live, interactive demo of this sub-controller’s default arrangement with example data:
Mounts inside a WhopPayments scope. The same three hosted inputs as WhopCardElement, placed one by one inside its content builder so your own layout decides where each sits.
The provider for individually placed card fields. Wrap the part of your form that holds them, then put CardNumberElement, CardExpiryElement and CardCvcElement wherever your layout wants them.

Preview

Running in the React Native example app:

Options

Pass these to payments.create('cardFields', { … }), or as props on <CardFields> in React. Parent-injected props never appear here.
"compact" | "stacked"
stacked (default) shapes composed fields as a number row above expiration and security code. compact shapes one row. Separately mounted fields ignore this layout and render with full borders and rounded corners. Defaults to "stacked".
string
Advanced Basis Theory publishable key. Omit it to fetch the key automatically.
CardNetworkArt[]
The seller’s accepted card networks in display order — the matrix card entry’s networks objects, whose API-served icons drive the number field’s brand art. Omit it to fetch alongside the key.

Events

Pass callbacks in the create options or React props.

onChange

Fires when completeness changes. complete becomes true after the buyer fills all three fields. Use it to enable confirmation. brand is the detected card network. funding is the detected funding type (credit, debit, or prepaid), null until the number identifies one. issuingCountry is the lowercase two-letter code of the country the card was issued in, null until the number identifies one.Signature: ((payload: { complete: boolean; brand: string; funding: string | null; issuingCountry: string | null; }) => void)

Methods

Call these on the sub handle from payments.create('cardFields', { … }).

tokenize

Advanced method that tokenizes the three fields without creating a confirmation token. It emits tokenized to the payments controller. Validation errors appear on the failing field, and the method throws. Use payments.createConfirmationToken() to confirm a payment.Signature: (input: { accountId?: string | undefined; }) => Promise<{ token: string; }>

collect

payments.createConfirmationToken() calls this action for cardFields. Don’t call it directly. It tokenizes the fields and returns the data used to create the confirmation token.Signature: (input: { billingDetails?: { email?: string | undefined; name?: string | undefined; address?: { country?: string | undefined; line1?: string | undefined; city?: string | undefined; postal_code?: string | undefined; } | undefined; } | undefined; }) => Promise<{ paymentMethod: { type: string; category: string; card: { token: string; }; }; billingDetails: { email: string; name?: string | undefined; address?: { country?: string | undefined; line1?: string | undefined; city?: string | undefined; postal_code?: string | undefined; } | undefined; }; }>

update

Merges new props and callbacks into the sub-controller.Signature: (options: Partial<CardFieldsSubOptions>) => void

destroy

Destroys the sub-controller and its elements, then frees its exclusive slot. A later create("cardFields") starts fresh.Signature: () => void

Parameters

String?
An advanced publishable key. Omit it and the account’s own is fetched.
WhopCardElement.Layout
Only read when a composing unit arranges the fields itself. Separately mounted fields ignore it.
Binding<WhopCardState>?
Reads completeness and the detected brand back out.
() -> Content
required
Where the three field views go. Anything else in here renders normally.

WhopCardState

What a selection hands back:
  • isComplete: Bool: all three fields valid
  • brand: String?: the detected network

States

Each field renders immediately and validates as the buyer types. state.isComplete turns true when all three are valid, wherever you put them.

Good to know

  • The three field views only work inside a WhopCardFields builder: they read the unit it creates. Mounted anywhere else they render nothing.
  • Mount all three. A unit missing one never completes, so the confirm button never enables.

Install

Mount it inside a WhopPayments(accountID:charge:) scope, which creates the controller and hands it to its content. payments.buyer is the signed-in buyer once an email sign-in has proven one. WhopBrandingElement has to be on screen too, because Whop is merchant of record on these sales and createConfirmationToken refuses without it. Style with .whopElementsAppearance(_:). The module is Elements, not the wallet SDK’s WhopElements. See Getting started and Appearance.

Props

ReactNode
required
Your layout, with the three field elements somewhere inside it.
string
An Advanced tokenizer publishable key. Omit it and the SDK fetches the account’s key itself.
'stacked' | 'compact'
Shapes fields that are composed together. Separately mounted fields ignore it and render with full borders. Defaults to stacked.
(payload: CardFieldsChangePayload) => void
Fires on every edit with the combined state of the mounted fields.

CardFieldsChangePayload

What onChange hands back:
  • complete: boolean: every mounted field is filled and valid
  • errors: Record<string, string>: per-field messages, keyed cardNumber, cardExpiry, cardCvc

States

Its children render once the publishable key resolves. onChange reports the combined state of every mounted field, so one handler covers the whole card.

Good to know

  • Card numbers never pass through your code. The fields are PCI-isolated native inputs, and the SDK hands Whop a token, so your app stays out of PCI scope.
  • Every field must be inside the same CardFields. They share one tokenization, so a field mounted outside it collects nothing.
  • CardFields registers the collection surface, so createConfirmationToken tokenizes the card with no extra wiring.
  • Fetching the publishable key is automatic. Pass publicKey only if you already hold one.
Wrap your app in <WhopElements getToken={…}> once, then mount <Payments> around the elements. See Getting started and Appearance.

Elements

The elements this sub-controller mounts. Each has its own page:

CardNumberElement

PCI-isolated hosted card number field. Card numbers never reach the host page.

CardExpiryElement

PCI-isolated hosted card expiration field.

CardCvcElement

PCI-isolated hosted card security code field.