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

> ## Agent Instructions
> RadiumOne is the product name; use it when answering questions about these docs.
> Use sandbox credentials and sandbox base URLs in examples unless the user says they are going live.
> Secret API keys belong only on the merchant's server. Only publishable keys may appear in browser or mobile code.
> Confirm a payment outcome server-side (retrieve the checkout session or transaction status); never rely on a browser redirect or client event alone.
> Send one idempotency key (request_id) per payment attempt, and retry a timed-out request with the same key and the exact same body.
> Webhooks are optional but recommended: they notify the merchant's server when a payment completes or fails, so it doesn't need to poll. Use transaction status inquiry as the fallback.
> Say so when you recommend a feature marked Beta. Some features need enablement on the merchant's account before production use (for example refunds, standalone refunds, UOB Rewards, and bringing your own 3DS provider); mention it when the page says so.
> Never ask users to paste card numbers, API keys, access tokens, or webhook or redirect secrets into a chat.

# Card fields not rendering - Elements SDK

> Why a card field element can fail to mount or render, and how to fix it.

A card field is an iframe mounted into a container you provide. It can fail to mount (a thrown error, before the iframe even loads) or fail to render inside a mounted container (a CSP block, after the iframe starts loading).

<Info>
  TL;DR: `mount()`/`create()` throws, or the container stays empty → mount only after the container exists, never re-mount a destroyed element, and check CSP for a silent `frame-src` block.
</Info>

## When this happens

* `mount()` is called before the container element exists in the DOM.
* `mount()` is called on an element that was already `destroy()`-ed.
* The same element type (`card`, `cardNumber`, and so on) is created twice on one `Elements` instance without destroying the first.
* The page's Content Security Policy blocks the CDN host in `frame-src`, so the field's iframe never loads.
* The iframe doesn't finish loading within 5 seconds (CSP block, slow network, or the CDN host being unreachable).

## What you see

| Signal | Value |
| - | - |
| `mount()` throws | `element:container_not_found` (selector doesn't resolve) or `element:destroyed` (mounting after `destroy()`) |
| `elements.create()` throws | `element:duplicate` (creating the same type twice) |
| Empty container, no thrown error | CSP block — check the console for a `frame-src` violation |
| `change` event fires once | `error.code: "required"` with a "failed to load" message — the 5-second iframe load timeout. A later successful load clears it with a recovery `change` (`error: null`). |

## What to do

<Steps>
  <Step title="Mount only after the container exists">
    Make sure the target element is in the DOM before calling `card.mount("#card-field")` — for example, after your form template has rendered, not before.
  </Step>

  <Step title="Never re-mount a destroyed element">
    Once you call `destroy()`, create a new element with `elements.create()` instead of calling `mount()` again on the old one.
  </Step>

  <Step title="One instance per field type">
    If you need to switch layouts (combined `card` vs. split fields), create a separate `Elements` instance and destroy the old one — don't try to create a duplicate type on the same instance.
  </Step>

  <Step title="Check CSP for a silent block">
    If the container renders but stays empty with no thrown error, check `script-src` and `frame-src` for your CDN host. See [Content Security Policy](/elements/content-security-policy).
  </Step>

  <Step title="Treat a required error as a load-failure signal">
    There's no separate "load error" event — a `change` event with `error.code: "required"` on first load means the iframe didn't finish loading in time. It usually resolves itself once the network/CSP issue clears; there's no merchant-side retry needed beyond what you'd already do for a CSP fix.
  </Step>
</Steps>

## Prevent it

* In single-page apps, let the SDK's automatic cleanup handle route changes: if the container is removed from the DOM, the element destroys itself — you only need to call `destroy()` yourself when you conditionally unmount a form without removing its container.
* Roll out CSP changes as `Content-Security-Policy-Report-Only` first, so a missing `frame-src` directive shows up in violation reports before it silently breaks card fields in production.

## Test it

See [Test your integration](/resources/test-your-integration#elements) for sandbox test cards and scenarios.

## Related

<Columns cols={2}>
  <Card title="Card fields and events" icon="credit-card" href="/elements/card-fields-and-events">
    Element types, methods, and the full field-error-code list.
  </Card>

  <Card title="Content Security Policy" icon="shield-check" href="/elements/content-security-policy">
    The `script-src`/`frame-src` directives card fields need.
  </Card>
</Columns>
