# `createCardField()`

Creates an embedded card input field for collecting card details directly on your page. The card field is rendered in a PCI-compliant iframe, allowing you to accept card payments without handling sensitive card data.

**Key features:**

- PCI-compliant iframe for secure card data collection
- Customisable styles and classes for seamless UI integration
- Real-time validation with error callbacks
- Support for saved payment methods
- Built-in loading indicators

:::info
For a complete implementation guide with examples, see: [Accept card payments via card field - Web](/docs/guides/merchant/accept-payments/online-payments/card-payments/web/card-field)
:::

:::info
For production card payments, provide `billingAddress` when creating the widget or when calling `submit()`. Some sandbox payments may still succeed without it, but issuers may decline more transactions in production.
:::

## Type signature

```typescript
RevolutCheckoutInstance.createCardField(
  options: CardFieldOptions
): RevolutCheckoutCardField

interface CardFieldOptions {
  target: HTMLElement
  onSuccess?: () => void
  onError?: (error: RevolutCheckoutError) => void
  onValidation?: (errors: ValidationError[]) => void
  onCancel?: () => void
  onStatusChange?: (status: FieldStatus) => void
  locale?: Locale | 'auto'
  styles?: FieldStyles
  classes?: FieldClasses
  theme?: 'light' | 'dark'
  hidePostcodeField?: boolean
  showLoadingIndicator?: boolean
  savePaymentMethodFor?: 'merchant' | 'customer'
  name?: string
  email?: string
  phone?: string
  billingAddress?: Address
  shippingAddress?: Address
}

interface RevolutCheckoutCardField {
  submit: (meta?: SubmitMeta) => void
  validate: () => void
  destroy: () => void
}
```

## Parameters

| Parameter | Description                                    | Type                                              | Required |
| --------- | ---------------------------------------------- | ------------------------------------------------- | -------- |
| `options` | Configuration object for the card field widget | [`CardFieldOptions`](#cardfieldoptions-interface) | Yes      |

### `CardFieldOptions` interface

| Parameter              | Description                                                                                                                        | Type                                                   | Required |
| ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------ | -------- |
| `target`               | DOM element where the card field iframe should be mounted                                                                          | `HTMLElement`                                          | Yes      |
| `onSuccess`            | Callback triggered when payment completes successfully                                                                             | `() => void`                                           | No       |
| `onError`              | Callback triggered when payment fails. Receives [`RevolutCheckoutError`](/docs/sdks/merchant-web-sdk/types/revolut-checkout-error) | `(error: RevolutCheckoutError) => void`                | No       |
| `onValidation`         | Callback triggered when card field validation state changes                                                                        | `(errors: ValidationError[]) => void`                  | No       |
| `onCancel`             | Callback triggered when user cancels payment                                                                                       | `() => void`                                           | No       |
| `onStatusChange`       | Callback triggered when field status changes (focused, invalid, empty, etc.)                                                       | `(status: FieldStatus) => void`                        | No       |
| `locale`               | Widget language                                                                                                                    | `Locale \| 'auto'` (default: `'auto'`)                 | No       |
| `styles`               | Styles applied to different states inside the secure iframe                                                                        | [`FieldStyles`](#fieldstyles)                          | No       |
| `classes`              | CSS classes applied to the target element for different states                                                                     | [`FieldClasses`](#fieldclasses)                        | No       |
| `theme`                | Color scheme of the widget                                                                                                         | `'light' \| 'dark'` (default: `'light'`)               | No       |
| `hidePostcodeField`    | Don't ask for postcode inside the card field. When enabled, provide full `billingAddress` in `submit()`                            | `boolean` (default: `false`)                           | No       |
| `showLoadingIndicator` | Show loading popup if payment remains pending                                                                                      | `boolean` (default: `false`)                           | No       |
| `savePaymentMethodFor` | Save payment method for future use                                                                                                 | `'merchant' \| 'customer'`                             | No       |
| `name`                 | Pre-fill cardholder name in format "FirstName LastName"                                                                            | `string`                                               | Yes\*    |
| `email`                | Pre-fill customer's email address                                                                                                  | `string`                                               | No       |
| `phone`                | Pre-fill customer's phone number                                                                                                   | `string`                                               | No       |
| `billingAddress`       | Provide or pre-fill customer's billing address for card payments                                                                   | [`Address`](/docs/sdks/merchant-web-sdk/types/address) | Yes\*    |
| `shippingAddress`      | Pre-fill customer's shipping address                                                                                               | [`Address`](/docs/sdks/merchant-web-sdk/types/address) | No       |

\* Required for card payments unless provided later in `submit()`.

#### `FieldStyles`

```typescript
type FieldStyles = {
  default?: Partial<CSSStyleDeclaration>
  focused?: Partial<CSSStyleDeclaration>
  invalid?: Partial<CSSStyleDeclaration>
  empty?: Partial<CSSStyleDeclaration>
  autofilled?: Partial<CSSStyleDeclaration>
  completed?: Partial<CSSStyleDeclaration>
}
```

Styles object for customising the card field appearance inside the secure iframe.

| Property     | Description                                         | Type                           |
| ------------ | --------------------------------------------------- | ------------------------------ |
| `default`    | Base styles always applied regardless of state      | `Partial<CSSStyleDeclaration>` |
| `focused`    | Applied when user focuses inside the input          | `Partial<CSSStyleDeclaration>` |
| `invalid`    | Applied on validation error                         | `Partial<CSSStyleDeclaration>` |
| `empty`      | Applied when user hasn't entered any data           | `Partial<CSSStyleDeclaration>` |
| `autofilled` | Applied when user used browser autofill             | `Partial<CSSStyleDeclaration>` |
| `completed`  | Applied when card field is completed without errors | `Partial<CSSStyleDeclaration>` |

#### `FieldClasses`

```typescript
type FieldClasses = {
  default?: string
  focused?: string
  invalid?: string
  empty?: string
  autofilled?: string
  completed?: string
}
```

CSS classes applied to the target element outside the secure iframe. Default values:

| Property     | Default value                 | Description                    |
| ------------ | ----------------------------- | ------------------------------ |
| `default`    | `'rc-card-field'`             | Base class always applied      |
| `focused`    | `'rc-card-field--focused'`    | Applied when input is focused  |
| `invalid`    | `'rc-card-field--invalid'`    | Applied on validation error    |
| `empty`      | `'rc-card-field--empty'`      | Applied when field is empty    |
| `autofilled` | `'rc-card-field--autofilled'` | Applied when browser autofills |
| `completed`  | `'rc-card-field--completed'`  | Applied when field is complete |

#### `FieldStatus`

```typescript
type FieldStatus = {
  focused: boolean
  invalid: boolean
  empty: boolean
  autofilled: boolean
  completed: boolean
}
```

Status object passed to `onStatusChange` callback, indicating current field state.

## Return value

```typescript
RevolutCheckoutCardField

interface RevolutCheckoutCardField {
  submit: (meta?: SubmitMeta) => void
  validate: () => void
  destroy: () => void
}
```

The method returns a `RevolutCheckoutCardField` object containing:

| Method     | Description                                         | Type                          |
| ---------- | --------------------------------------------------- | ----------------------------- |
| `submit`   | Submit card details with customer metadata          | `(meta?: SubmitMeta) => void` |
| `validate` | Manually trigger validation of entered card details | `() => void`                  |
| `destroy`  | Remove the card field and clean up resources        | `() => void`                  |

### `submit(meta)`

The `submit()` method accepts an optional `SubmitMeta` object containing customer information:

```typescript
type SubmitMeta = {
  name?: string
  email?: string
  phone?: string
  savePaymentMethodFor?: 'merchant' | 'customer'
  billingAddress?: Address
  shippingAddress?: Address
}
```

| Parameter              | Description                                                                                                       | Type                                                   | Required |
| ---------------------- | ----------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------ | -------- |
| `name`                 | Cardholder name in format "FirstName LastName"                                                                    | `string`                                               | No\*     |
| `email`                | Customer's email address                                                                                          | `string`                                               | No\*     |
| `phone`                | Customer's phone number                                                                                           | `string`                                               | No       |
| `savePaymentMethodFor` | Save payment method for `'customer'` (customer-initiated) or `'merchant'` (merchant-initiated recurring payments) | `'merchant' \| 'customer'`                             | No       |
| `billingAddress`       | Customer's billing address                                                                                        | [`Address`](/docs/sdks/merchant-web-sdk/types/address) | Yes\*    |
| `shippingAddress`      | Customer's shipping address (displayed in Merchant Dashboard only)                                                | [`Address`](/docs/sdks/merchant-web-sdk/types/address) | No       |

\* Required for card payments unless already provided in `createCardField()`

`name` is the cardholder name used in the payment flow. There is no separate `cardholderName` field in `SubmitMeta`.

## Callback events

The card field provides callback functions for handling payment lifecycle events in your frontend.

:::warning
Widget callbacks are not guaranteed to fire due to network issues, browser closures, or ad-blockers. Always use [webhooks](/docs/guides/merchant/monitor-and-observe/webhooks/using-webhooks) for critical backend operations like order fulfilment.
:::

### `onSuccess`

```typescript
() => void
```

Triggered when the payment completes successfully.

**Use cases:**

- Display success message to the customer
- Redirect to order confirmation page
- Update UI to reflect successful payment

**Example:**

```typescript
onSuccess: () => {
  console.log('Payment successful!')
  window.location.href = '/confirmation'
}
```

### `onError`

```typescript
(error: RevolutCheckoutError) => void
```

Triggered when the payment fails. The `error` parameter is a [`RevolutCheckoutError`](/docs/sdks/merchant-web-sdk/types/revolut-checkout-error) object containing error details.

**Use cases:**

- Display error message to the customer
- Log error for debugging
- Re-enable checkout form

**Example:**

```typescript
onError: (error) => {
  console.error('Payment failed:', error.message)
  alert(`Payment failed: ${error.message}`)
}
```

### `onValidation`

```typescript
(errors: ValidationError[]) => void
```

Triggered when card field validation state changes. Receives an array of [`ValidationError`](/docs/sdks/merchant-web-sdk/types/validation-error) objects. Empty array means all fields are valid.

**Use cases:**

- Display inline validation errors
- Enable/disable submit button based on validation state
- Track validation issues

**Example:**

```typescript
onValidation: (errors) => {
  if (errors.length === 0) {
    console.log('Card details are valid')
    submitButton.disabled = false
  } else {
    console.log('Validation errors:', errors)
    submitButton.disabled = true
  }
}
```

### `onCancel`

```typescript
() => void
```

Triggered when the user cancels the payment flow.

**Use cases:**

- Display cancellation message
- Re-enable checkout form
- Track abandonment analytics

**Example:**

```typescript
onCancel: () => {
  console.log('Payment cancelled')
  alert('Payment was cancelled. You can try again.')
}
```

### `onStatusChange`

```typescript
(status: FieldStatus) => void
```

Triggered when the card field status changes (focused, invalid, empty, autofilled, completed).

**Use cases:**

- Update UI based on field state
- Show/hide helper text
- Apply custom styling

**Example:**

```typescript
onStatusChange: (status) => {
  console.log('Field status:', status)
  if (status.completed && !status.invalid) {
    console.log('Card details are complete and valid')
  }
}
```

## Usage examples

- ![With async/await]

  ```typescript
  import RevolutCheckout from '@revolut/checkout'

  // Initialise with order token
  const instance = await RevolutCheckout(orderToken, 'prod')

  // Create card field
  const cardField = instance.createCardField({
    target: document.getElementById('card-field'),

    onSuccess: () => {
      console.log('Payment successful!')
      window.location.href = '/confirmation'
    },

    onError: (error) => {
      console.error('Payment failed:', error.message)
      alert(`Payment failed: ${error.message}`)
    },

    onValidation: (errors) => {
      const submitButton = document.getElementById('submit-button')
      submitButton.disabled = errors.length > 0
    },
  })

  // Handle form submission
  document.getElementById('submit-button').addEventListener('click', () => {
    cardField.submit({
      name: 'John Doe',
      email: 'john.doe@example.com',
      billingAddress: {
        countryCode: 'GB',
        postcode: 'EC1A 1BB',
        city: 'London',
        streetLine1: '1 Example Street',
      },
    })
  })
  ```

- ![Without async/await]

  ```typescript
  import RevolutCheckout from '@revolut/checkout'

  // Initialise with order token
  RevolutCheckout(orderToken, 'prod').then((instance) => {
    // Create card field
    const cardField = instance.createCardField({
      target: document.getElementById('card-field'),

      onSuccess: () => {
        console.log('Payment successful!')
        window.location.href = '/confirmation'
      },

      onError: (error) => {
        console.error('Payment failed:', error.message)
        alert(`Payment failed: ${error.message}`)
      },

      onValidation: (errors) => {
        const submitButton = document.getElementById('submit-button')
        submitButton.disabled = errors.length > 0
      },
    })

    // Handle form submission
    document.getElementById('submit-button').addEventListener('click', () => {
      cardField.submit({
        name: 'John Doe',
        email: 'john.doe@example.com',
        billingAddress: {
          countryCode: 'GB',
          postcode: 'EC1A 1BB',
          city: 'London',
          streetLine1: '1 Example Street',
        },
      })
    })
  })
  ```

### Pre-fill customer information

You can improve the checkout experience by pre-filling customer information:

```typescript
const cardField = instance.createCardField({
  target: document.getElementById('card-field'),
  name: 'John Doe',
  email: 'customer@example.com',
  billingAddress: {
    countryCode: 'GB',
    region: 'Greater London',
    city: 'London',
    postcode: 'EC1A 1BB',
    streetLine1: '1 Example Street',
    streetLine2: 'Flat 2B',
  },
  onSuccess: () => {
    window.location.href = '/confirmation'
  },
  onError: (error) => {
    alert(`Payment failed: ${error.message}`)
  },
})

// Submit without additional metadata since it's pre-filled
document.getElementById('submit-button').addEventListener('click', () => {
  cardField.submit()
})
```

### Save payment method for future use

You can save the customer's payment method for future payments using `savePaymentMethodFor`:

- `'customer'` - For customer-initiated future payments (express checkout, saved cards)
- `'merchant'` - For merchant-initiated recurring payments (subscriptions, auto-renewals)

```typescript
// Option 1: Set during card field creation
const cardField = instance.createCardField({
  target: document.getElementById('card-field'),
  savePaymentMethodFor: 'customer', // or 'merchant'

  onSuccess: () => {
    console.log('Payment successful and card saved!')
    window.location.href = '/confirmation'
  },

  onError: (error) => {
    alert(`Payment failed: ${error.message}`)
  },
})

document.getElementById('submit-button').addEventListener('click', () => {
  cardField.submit({
    name: 'John Doe',
    email: 'john.doe@example.com',
    billingAddress: {
      countryCode: 'GB',
      postcode: 'EC1A 1BB',
      city: 'London',
      streetLine1: '1 Example Street',
    },
  })
})
```

```typescript
// Option 2: Set at submit time
const cardField = instance.createCardField({
  target: document.getElementById('card-field'),

  onSuccess: () => {
    window.location.href = '/confirmation'
  },

  onError: (error) => {
    alert(`Payment failed: ${error.message}`)
  },
})

document.getElementById('submit-button').addEventListener('click', () => {
  cardField.submit({
    name: 'John Doe',
    email: 'john.doe@example.com',
    savePaymentMethodFor: 'customer', // or 'merchant'
    billingAddress: {
      countryCode: 'GB',
      postcode: 'EC1A 1BB',
      city: 'London',
      streetLine1: '1 Example Street',
    },
  })
})
```

## See also

- [Accept card payments via card field - Web](/docs/guides/merchant/accept-payments/online-payments/card-payments/web/card-field)
- [Token-based initialisation](/docs/sdks/merchant-web-sdk/initialisation/token-based)
- [Address type reference](/docs/sdks/merchant-web-sdk/types/address)
- [RevolutCheckoutError type reference](/docs/sdks/merchant-web-sdk/types/revolut-checkout-error)
- [ValidationError type reference](/docs/sdks/merchant-web-sdk/types/validation-error)
- [Use webhooks to keep track of the payment lifecycle](/docs/guides/merchant/monitor-and-observe/webhooks/using-webhooks)