Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.ozura.com/llms.txt

Use this file to discover all available pages before exploring further.

@ozura/elements/react ships a context provider, hooks, and pre-built field components for both card and bank payments.

Installation

npm install @ozura/elements
Import from the React-specific entrypoint:
import {
  OzElements,
  useOzElements,
  OzCard,
  OzCardNumber,
  OzExpiry,
  OzCvv,
  OzBankCard,
  OzBankAccountNumber,
  OzBankRoutingNumber,
} from '@ozura/elements/react';

OzElements Provider

Wrap your checkout UI with <OzElements>. It creates the OzVault instance and makes it available to all children via React context. pubKey and a session option are required.
import { OzElements } from '@ozura/elements/react';

export default function App() {
  return (
    <OzElements
      pubKey="YOUR_PUB_KEY"
      sessionUrl="/api/oz-session"
    >
      <CheckoutForm />
    </OzElements>
  );
}
sessionUrl is the simplest option — just pass your session endpoint path. See Server SDK — Session route for the matching backend route. For custom headers or auth tokens, use getSessionKey instead:
<OzElements
  pubKey="YOUR_PUB_KEY"
  getSessionKey={async (sessionId) => {
    const res = await fetch('/api/oz-session', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` },
      body: JSON.stringify({ sessionId }),
    });
    if (!res.ok) throw new Error(`Session endpoint returned HTTP ${res.status}`);
    const { sessionKey } = await res.json();
    return sessionKey;
  }}
>
  <CheckoutForm />
</OzElements>

OzElements props

PropTypeRequiredDefaultDescription
pubKeystringVault pub key (client-safe)
sessionUrlstring✅ ¹URL of your session endpoint — simplest option
getSessionKey(sessionId: string) => Promise<string>✅ ¹Custom callback for session key retrieval (custom headers, auth, etc.)
fetchWaxKey(sessionId: string) => Promise<string>✅ ¹Deprecated — use sessionUrl or getSessionKey
frameBaseUrlstringhttps://elements.ozura.comOverride iframe asset URL
fontsFontSource[][]Custom fonts to load in iframes
appearanceAppearanceGlobal theme and variable overrides. See Styling.
onLoadError() => voidCalled if vault fails to load
loadTimeoutMsnumber10000Only relevant when onLoadError is set: ms to wait before calling onLoadError
onSessionRefresh() => voidCalled when the SDK silently refreshes the session during a tokenization attempt
onReady() => voidCalled once when the vault is ready
sessionLimitnumber | null3Max successful tokenize calls per session before auto-refresh. Pass null to remove the cap. Must match sessionLimit in your server-side createSession call.
debugbooleanfalseEnables [OzVault]-prefixed console.log output at every lifecycle event. Safe in production — no sensitive data is logged. See API Reference — Debug mode.
childrenReactNodeYour checkout UI
¹ Exactly one of sessionUrl, getSessionKey, or fetchWaxKey is required.
Mount one card form at a time inside a single <OzElements> provider. If you render a second <OzCard> (or a second set of individual field components) without first unmounting the first, the older element iframes will be silently replaced. For multi-step flows, unmount one form before mounting the next.

useOzElements Hook

Use useOzElements() inside any component wrapped by <OzElements> to tokenize and track readiness.
import { useOzElements } from '@ozura/elements/react';

function CheckoutForm() {
  const { createToken, ready, initError } = useOzElements();

  if (initError) return <p>Payment unavailable — please refresh.</p>;

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    const { token, cvcSession, billing } = await createToken({
      billing: { firstName: 'Jane', lastName: 'Smith' },
    });
    // send token + cvcSession + billing to backend
  };

  return (
    <form onSubmit={handleSubmit}>
      <OzCardNumber />
      <OzExpiry />
      <OzCvv />
      <button type="submit" disabled={!ready}>Pay now</button>
    </form>
  );
}

useOzElements return values

ValueTypeDescription
createToken(opts?: TokenizeOptions) => Promise<TokenResponse>Tokenizes all mounted card elements
createBankToken(opts: BankTokenizeOptions) => Promise<BankTokenResponse>Tokenizes mounted bank account elements
reset() => voidClears all mounted card and bank element fields without destroying the vault or refreshing the session. Call this after a declined payment so the customer can re-enter their details. The session and its remaining budget are preserved.
readybooleantrue when the vault and all mounted fields are ready. Gate your submit button on this.
initErrorError | nullNon-null when vault initialization fails — e.g. pubKey is missing, session endpoint unreachable, or backend error. Render a fallback UI when set.
tokenizeCountnumberCount of successful createToken/createBankToken calls in the current session. Resets to 0 on every session refresh. Use this to display “X attempts remaining” feedback or disable the pay button while a background session refresh is completing.
ready is a composite flag. It is true only when the vault is ready AND every field component that has been mounted has also finished loading. Do not use vault.isReady directly — that only reflects vault readiness, not field readiness.

OzCard — Combined Card Component

OzCard renders card number, expiry, and CVV in a single component with built-in layout, loading skeletons, and inline error display. For maximum layout control, use the individual components instead.
import { OzElements, OzCard, useOzElements } from '@ozura/elements/react';

function CheckoutForm() {
  const { createToken, ready } = useOzElements();

  return (
    <form onSubmit={async (e) => {
      e.preventDefault();
      const { token, cvcSession } = await createToken({
        billing: { firstName: 'Jane', lastName: 'Doe' },
      });
      // send to backend
    }}>
      <OzCard layout="default" />
      <button type="submit" disabled={!ready}>Pay</button>
    </form>
  );
}

export default function App() {
  return (
    <OzElements pubKey="YOUR_PUB_KEY" sessionUrl="/api/oz-session">
      <CheckoutForm />
    </OzElements>
  );
}

OzCard props

PropTypeDefaultDescription
layout'default' | 'rows''default''default': card number on top, expiry + CVV side by side. 'rows': all three stacked vertically.
styleElementStyleConfigShared style applied to all three fields
styles{ cardNumber?, expiry?, cvv? }Per-field style overrides merged on top of style
classNames{ cardNumber?, expiry?, cvv?, row? }CSS class names for field wrappers and the expiry+CVV row container
labels{ cardNumber?, expiry?, cvv? }Labels rendered above each field
labelStyleReact.CSSPropertiesInline style applied to all label elements
labelClassNamestringCSS class applied to all label elements
placeholders{ cardNumber?, expiry?, cvv? }Placeholder overrides per field
gapnumber | string8Gap between fields (px number or any CSS value string)
hideErrorsbooleanfalseSuppress the built-in error display
errorStyleReact.CSSPropertiesInline style for the error message container
errorClassNamestringCSS class for the error message container
renderError(err: string) => ReactNodeCustom error renderer
onChange(state: OzCardState) => voidFires on any field change with aggregate state
onReady() => voidFires once all three field iframes are loaded
onFocus(field: 'cardNumber' | 'expiry' | 'cvv') => voidFires when a field gains focus
onBlur(field: 'cardNumber' | 'expiry' | 'cvv') => voidFires when a field loses focus
disabledbooleanDisables all inputs
classNamestringCSS class for the outer wrapper div

OzCardState

type OzCardState = {
  complete:   boolean;                      // all three fields complete and valid
  cardBrand?: string;                       // detected brand from card number field
  error?:     string;                       // first error from any field
  fields: {
    cardNumber: ElementChangeEvent | null;
    expiry:     ElementChangeEvent | null;
    cvv:        ElementChangeEvent | null;
  };
};

Individual Card Components

Use OzCardNumber, OzExpiry, and OzCvv when you need full layout control.
The expiry component is exported as OzExpiry, not OzExpirationDate.
import { OzCardNumber, OzExpiry, OzCvv } from '@ozura/elements/react';

function CardFields() {
  return (
    <div className="card-form">
      <div className="field">
        <label>Card number</label>
        <OzCardNumber />
      </div>
      <div className="row">
        <div className="field">
          <label>Expiry</label>
          <OzExpiry />
        </div>
        <div className="field">
          <label>CVV</label>
          <OzCvv />
        </div>
      </div>
    </div>
  );
}

OzFieldProps (all individual field components)

PropTypeDescription
styleElementStyleConfigStyle overrides for this field
placeholderstringPlaceholder text
disabledbooleanDisables the input
loadTimeoutMsnumberOverride the iframe load timeout for this field
classNamestringCSS class applied to the wrapper <div>
onChange(event: ElementChangeEvent) => voidFired on value or state change
onFocus() => voidFired when the field receives focus
onBlur() => voidFired when the field loses focus
onReady() => voidFired when the iframe is loaded and interactive
onLoadError(error: string) => voidFired if the iframe fails to load

OzBankCard — Combined Bank Component

OzBankCard renders account number and routing number in a single component with built-in layout, loading skeletons, and inline error display.
import { OzElements, OzBankCard, useOzElements } from '@ozura/elements/react';

function BankForm() {
  const { createBankToken, ready } = useOzElements();
  const [firstName, setFirstName] = React.useState('');
  const [lastName, setLastName]   = React.useState('');

  return (
    <form onSubmit={async (e) => {
      e.preventDefault();
      const { token, bank } = await createBankToken({ firstName, lastName });
      // send token to your ACH processor backend
    }}>
      <input value={firstName} onChange={e => setFirstName(e.target.value)} placeholder="First name" />
      <input value={lastName}  onChange={e => setLastName(e.target.value)}  placeholder="Last name" />
      <OzBankCard />
      <button type="submit" disabled={!ready}>Submit</button>
    </form>
  );
}

export default function App() {
  return (
    <OzElements pubKey="YOUR_PUB_KEY" sessionUrl="/api/oz-session">
      <BankForm />
    </OzElements>
  );
}

OzBankCard props

PropTypeDefaultDescription
styleElementStyleConfigShared style applied to both fields
styles{ accountNumber?, routingNumber? }Per-field style overrides
classNames{ accountNumber?, routingNumber? }CSS class names for field wrappers
labels{ accountNumber?, routingNumber? }Labels rendered above each field
labelStyleReact.CSSPropertiesInline style applied to all label elements
labelClassNamestringCSS class applied to all label elements
placeholders{ accountNumber?, routingNumber? }Placeholder overrides per field
gapnumber | string8Gap between fields
hideErrorsbooleanfalseSuppress the built-in error display
errorStyleReact.CSSPropertiesInline style for the error message container
errorClassNamestringCSS class for the error message container
renderError(err: string) => ReactNodeCustom error renderer
onChange(state: OzBankCardState) => voidFires on either field change with aggregate state
onReady() => voidFires once both field iframes are loaded
onFocus(field: 'accountNumber' | 'routingNumber') => voidFires when a field gains focus
onBlur(field: 'accountNumber' | 'routingNumber') => voidFires when a field loses focus
disabledbooleanDisables all inputs
classNamestringCSS class for the outer wrapper div

OzBankCardState

type OzBankCardState = {
  complete: boolean;                          // both fields complete and valid
  error?:   string;                           // first error from either field
  fields: {
    accountNumber: ElementChangeEvent | null;
    routingNumber: ElementChangeEvent | null;
  };
};

Individual Bank Components

Use OzBankAccountNumber and OzBankRoutingNumber for full layout control. They accept the same OzFieldProps as card fields.
import { OzBankAccountNumber, OzBankRoutingNumber } from '@ozura/elements/react';

function BankFields() {
  return (
    <>
      <div>
        <label>Account number</label>
        <OzBankAccountNumber placeholder="Account number" />
      </div>
      <div>
        <label>Routing number</label>
        <OzBankRoutingNumber placeholder="Routing number" />
      </div>
    </>
  );
}

Full Card Checkout Example

import { useState } from 'react';
import { OzElements, useOzElements, OzCard } from '@ozura/elements/react';
import { OzError } from '@ozura/elements';

function CheckoutForm() {
  const { createToken, reset, ready, initError } = useOzElements();
  const [error, setError]   = useState<string | null>(null);
  const [loading, setLoading] = useState(false);

  if (initError) return <p>Payment fields unavailable — please refresh.</p>;

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    setError(null);
    setLoading(true);

    try {
      const { token, cvcSession, billing } = await createToken({
        billing: {
          firstName: 'Jane',
          lastName:  'Smith',
          address: {
            line1:   '123 Main St',
            city:    'San Francisco',
            state:   'CA',
            zip:     '94102',
            country: 'US',
          },
        },
      });

      const res = await fetch('/api/charge', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ token, cvcSession, billing }),
      });

      if (!res.ok) throw new Error('Payment failed');
      window.location.href = '/success';
    } catch (err) {
      reset();                           // clear fields so customer can re-enter
      setError(err instanceof OzError ? err.message : 'Something went wrong.');
    } finally {
      setLoading(false);
    }
  };

  return (
    <form onSubmit={handleSubmit} className="checkout-form">
      <OzCard layout="default" />
      {error && <p className="error">{error}</p>}
      <button type="submit" disabled={!ready || loading}>
        {loading ? 'Processing…' : 'Pay'}
      </button>
    </form>
  );
}

export default function App() {
  return (
    <OzElements
      pubKey="YOUR_PUB_KEY"
      sessionUrl="/api/oz-session"
      appearance={{ theme: 'flat', variables: { colorPrimary: '#6366f1' } }}
      onLoadError={() => console.error('Payment fields failed to load')}
    >
      <CheckoutForm />
    </OzElements>
  );
}

Next Steps

Styling

Customize field appearance with style config and global appearance.

Error Handling

Handle OzError codes and surface them to users.

Card Elements Reference

All card options, events, and methods.

Bank Elements Reference

All bank options, events, and methods.