Field Components
@accrupay/react exports five field components: CardholderName, CardNumber, CardExpiry, CardCVC, and SubmitButton. All must be rendered inside an <AccruPay> provider.
CardholderName
Renders a provider-appropriate text input for the name on the card. For providers that require SDK-managed name input, the component renders the provider's own element; otherwise it renders a standard HTML <input>.
Accepts all standard React.InputHTMLAttributes<HTMLInputElement> except value (the field is uncontrolled internally).
| Prop | Type | Notes |
|---|---|---|
className | string | Applied to the input element. |
style | React.CSSProperties | Inline styles. |
placeholder | string | Placeholder text. |
onChange | React.ChangeEventHandler<HTMLInputElement> | Standard change handler. |
onBlur | React.FocusEventHandler<HTMLInputElement> | Standard blur handler. |
disabled | boolean | Disables the input. |
autoComplete | string | Recommend "cc-name". |
| Any other input attr | — | Passed through to the underlying element. |
<CardholderName
placeholder="Name on card"
autoComplete="cc-name"
className="input"
onChange={(e) => console.log(e.target.value)}
/>
CardNumber, CardExpiry, CardCVC
These components render provider-hosted embedded fields — secure iframes or SDK-injected inputs from the payment provider. They do not accept input event handlers (onChange, onBlur, onFocus, value, etc.). Adding those props has no effect.
Use isReady from useAccruPay to know when these fields are interactive and ready to accept input.
Each component accepts only layout props:
| Prop | Type | Description |
|---|---|---|
className | string | CSS class applied to the wrapper element. |
style | React.CSSProperties | Inline styles on the wrapper element. |
<CardNumber className="card-field" style={{ marginBottom: 12 }} />
<CardExpiry className="card-field" />
<CardCVC className="card-field" />
Style the wrapper via className and style. The embedded field inside fills the wrapper. Set a fixed height (typically 40–56 px) to ensure the field is visible — embedded fields do not inherit height from content flow.
SubmitButton
A button that calls submitPayment() on click. Extends React.ButtonHTMLAttributes<HTMLButtonElement> with additional callbacks.
| Prop | Type | Required | Description |
|---|---|---|---|
children | ReactNode | yes | Button label. |
onSuccess | (result: any) => void | no | Called with the provider result on successful payment. |
onError | (error: Error) => void | no | Called with the thrown error on failure. |
submitParams | AccruPayTransactionSubmitParams | no | Billing override passed to submitPayment(). |
disabled | boolean | no | Disables the button. Combined with internal isProcessing check. |
| Any other button attr | — | — | Passed through to the underlying <button>. |
<SubmitButton
className="pay-button"
disabled={!isReady}
onSuccess={(result) => router.push('/order/confirmed')}
onError={(err) => console.error(err)}
>
Pay now
</SubmitButton>
SubmitButton is disabled automatically while isProcessing is true, regardless of the disabled prop.
For custom submission logic (async billing lookup, form validation before submit), call submitPayment() from useAccruPay directly rather than using SubmitButton.
Styling
None of the field components ship built-in styles. Wrap them in your own layout elements.
<div className="card-form">
<label>Name on card</label>
<CardholderName className="input" placeholder="Jane Smith" autoComplete="cc-name" />
<label>Card number</label>
<CardNumber className="input embedded" style={{ height: 48 }} />
<div className="card-form__row">
<div>
<label>Expiry</label>
<CardExpiry className="input embedded" style={{ height: 48 }} />
</div>
<div>
<label>CVC</label>
<CardCVC className="input embedded" style={{ height: 48 }} />
</div>
</div>
</div>
Complete form example
import {
AccruPay,
CardholderName,
CardNumber,
CardExpiry,
CardCVC,
SubmitButton,
useAccruPay,
} from '@accrupay/react';
function CheckoutForm() {
const { isReady, error } = useAccruPay();
return (
<div className="form">
<div className="field">
<label htmlFor="name">Name on card</label>
<CardholderName
id="name"
className="input"
placeholder="Jane Smith"
autoComplete="cc-name"
/>
</div>
<div className="field">
<label>Card number</label>
<CardNumber className="input" style={{ height: 48 }} />
</div>
<div className="field-row">
<div className="field">
<label>Expiry</label>
<CardExpiry className="input" style={{ height: 48 }} />
</div>
<div className="field">
<label>CVC</label>
<CardCVC className="input" style={{ height: 48 }} />
</div>
</div>
{error && <p className="error">{error}</p>}
<SubmitButton
className="btn-primary"
disabled={!isReady}
onSuccess={() => window.location.href = '/confirmed'}
onError={(err) => console.error(err)}
>
Pay now
</SubmitButton>
</div>
);
}
export function Checkout({ sessionId }: { sessionId: string }) {
return (
<AccruPay
merchantPublicId={process.env.NEXT_PUBLIC_ACCRUPAY_MERCHANT_ID!}
transactionSessionId={sessionId}
>
<CheckoutForm />
</AccruPay>
);
}