> ## Documentation Index
> Fetch the complete documentation index at: https://docs.avraapi.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Render Customer Form

> Collect buyer details with a configurable, accessible form and send them only to your backend.

`renderForm()` renders the buyer-details form used before your backend creates a payment session. It collects data; it does not create an order, contact a gateway, or confirm payment.

Create the Elements instance once, then render into a CSS selector or an existing DOM `Element`.

```html theme={null}
<div id="payment-customer"></div>
```

```js theme={null}
const form = elements.renderForm('#payment-customer', {
  title: 'Billing details',
  theme: 'dark',
  accentColor: '#3fcef1',
  backgroundColor: '#0c1631',
  textColor: '#f8fafc',
  borderColor: '#3a485f',
  padding: '24px',
  defaultCountry: 'LK',
  phoneDefaultCountry: 'LK',
  syncPhoneCountry: true,
});
```

Calling `renderForm()` again on the same Elements instance destroys the previous form before mounting the new one. Call `form.destroy()` or `elements.destroy()` when your checkout page unmounts.

## Customer fields

The package renders these fields in this order.

| Field key | Default label | Default requirement | Browser input |
| - | - | - | - |
| `first_name` | First name | Required | Text |
| `last_name` | Last name | Required | Text |
| `email` | Email address | Required | Email |
| `phone` | Phone number | Required | Telephone with a country dial-code selector |
| `address_line_1` | Address line 1 | Required | Text |
| `address_line_2` | Address line 2 | Optional | Text |
| `country` | Country | Required | Searchable country selector |
| `city` | City | Required | Text |
| `district` | District | Optional | Text |
| `province` | Province | Optional | Text |
| `zip` | ZIP / postal code | Optional | Text |

The country selector has keyboard access and search. On narrow screens, the form becomes a single column.

## All `renderForm()` options

| Option | Type | Default | Behaviour |
| - | - | - | - |
| `title` | string | `Customer details` | Heading shown on the collapsible form summary. |
| `collapsed` | boolean | `false` | Starts the fields closed when `true`. Buyers can open or close the form summary. |
| `theme` | `light`, `dark`, `auto` | `auto` | Shared appearance option. Use explicit `light` or `dark` for a fixed surface. |
| `accentColor` | CSS colour | `#2563eb` | Focus, selected, and interactive accent colour. |
| `backgroundColor` | CSS colour | Theme default | Form surface and floating-label background. |
| `textColor` | CSS colour | Theme default | Primary text colour. |
| `borderColor` | CSS colour | Theme default | Outer, input, and selector borders. |
| `padding` | CSS length | `20px` | Outer form padding. |
| `exclude` | string array | `[]` | Fields to omit, subject to the required/optional rule below. Accepts `address-line-2` or `address_line_2`. |
| `required` | string array | `[]` | Makes optional fields required. Uses canonical underscore field keys. |
| `optional` | string array | `[]` | Makes default-required fields optional. It also allows one of those fields to be excluded. |
| `labels` | object | `{}` | Replaces labels by canonical field key, for example `{ zip: 'Postcode' }`. |
| `defaultCountry` | ISO 3166-1 alpha-2 code | `LK` | Initial billing country. Invalid codes fall back to `LK`. |
| `phoneDefaultCountry` | ISO 3166-1 alpha-2 code | `defaultCountry` | Initial phone dial-code country. Invalid codes fall back to `LK`. |
| `syncPhoneCountry` | boolean | `true` | When `true`, changing billing country also changes the phone dial-code country. |

### Required, optional, and excluded fields

Default-required fields remain visible even if listed in `exclude`. To omit a default-required field, first make it optional.

```js theme={null}
elements.renderForm('#payment-customer', {
  optional: ['phone'],
  exclude: ['phone', 'address-line-2', 'district'],
  required: ['zip'],
});
```

This keeps the standard required fields, removes the now-optional phone field plus two optional fields, and makes ZIP/postal code required.

<Warning>
  Browser `required` attributes improve the buyer experience, but they are not your payment validation boundary. Validate every field again in your backend before calling `createOrder()`.
</Warning>

### Labels and a compact form

```js theme={null}
elements.renderForm('#payment-customer', {
  title: 'Customer details',
  collapsed: true,
  labels: {
    first_name: 'Given name',
    last_name: 'Family name',
    address_line_1: 'Street address',
    zip: 'Postcode',
  },
  optional: ['district', 'province'],
  exclude: ['district', 'province'],
});
```

## Read the form result

`form.value()` returns the fields currently rendered by the component. It returns the country **name**, the phone number in an E.164-style format, and the selected dial code.

```js theme={null}
const customer = form.value();

// Representative result. Your backend must validate it.
console.log(customer);
```

```json theme={null}
{
  "first_name": "Maya",
  "last_name": "Perera",
  "email": "maya@example.com",
  "phone": "+94771234567",
  "phone_dial_code": "+94",
  "address_line_1": "42 Lake Road",
  "address_line_2": "",
  "country": "Sri Lanka",
  "city": "Colombo",
  "district": "",
  "province": "",
  "zip": "00300"
}
```

If a buyer enters a phone number beginning with `+`, the package preserves that international number after removing spaces and common punctuation. Otherwise it combines the selected dial code with the entered national number and removes one leading `0` from that local part.

Do not use this client-side normalization as proof that a phone number is valid or owned. Apply your own server-side validation and any gateway-specific requirements.

## Send details to your backend endpoint

`checkout()` reads the mounted form automatically and passes its value to the `createOrder` callback together with the selected gateway, mode, and public `providerOptions`.

```js theme={null}
const elements = AvraAPIPaymentElements.create({
  createOrder: ({ gateway, mode, customer, providerOptions }) =>
    fetch('/your-checkout-endpoint', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ gateway, mode, customer, providerOptions }),
    }).then(async (response) => {
      const session = await response.json();
      if (!response.ok) throw Object.assign(new Error('Checkout could not be prepared.'), session?.error ?? {});
      return session;
    }),
});
```

`/your-checkout-endpoint` is a placeholder for a route in **your** application. Your backend loads its own order, checks the allowed method against fresh availability, validates `customer`, and uses the AvraAPI SDK. It must not accept a browser value as the final amount, currency, order ID, gateway environment, or completion authority.

Continue with [Render Payment Methods](/universal-payment-gateway/payment-elements/render-methods).

## Visual & Samples

A dedicated Visual & Samples page will provide the approved light and dark examples with the exact code used to create each view. It will be linked here when its visual layout and screenshots are finalized.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.