Collection module UI components
How to add UI components for collecting and managing payment details.
Add custom collection module UI components to create, display, and summarise payment methods in Root Dashboard and Root Embed.
These components let your collection module return HTML that Root renders inside an iframe. Use them to collect payment provider data, show payment method details, and display a compact payment method summary.
Render create payment method
The renderCreatePaymentMethod function renders the UI for creating a new payment method. When a customer in Embed or a user in Root Dashboard selects the collection module payment method, Root fetches and renders the HTML returned by this function.
Use this component to collect the payment provider data required to create a payment method. The content is rendered inside an iframe and communicates with Root using the exposed functions described below.
The renderCreatePaymentMethod function accepts a single params object.
| Parameter | Type | Required | Description |
|---|---|---|---|
policy | Object | No | Used when the payment method is being created for a policy. |
application | Object | No | Used when the payment method is being created for an application. |
policyholder | Object | No | The policyholder the payment method is being created for, when available. Root Dashboard and Embed usually pass this value in current flows, but the hook contract allows it to be undefined. |
Render functions can return the HTML string directly or return a promise that resolves to the HTML string.
// Create content to be returned in Root Dashboard and Embed.
const renderCreatePaymentMethod = (params: {
application?: Record<string, any>;
policyholder?: Record<string, any>;
policy?: Record<string, any>;
}) => {
return `<!DOCTYPE html>
<html lang="en">
<head></head>
<body>
<div id="payment-element"></div>
<script></script>
</body>
</html>`;
};Create payment method lifecycle
Root exposes helper functions inside the iframe so your collection module can submit the payment method form and pass the result back to Root.
You implement submitCreatePaymentMethod. Root injects completeCreatePaymentMethod, setIsLoading, and setIsValid into the iframe. Call these injected functions, but do not redefine them.
The create payment method flow is:
- Root renders the HTML returned by
renderCreatePaymentMethod. - The user completes the payment method form.
- Root calls
submitCreatePaymentMethodwhen the user submits the form. - Your module validates or submits the payment data to the payment provider.
- Your module calls
completeCreatePaymentMethod(result). - Root invokes the collection module's
createPaymentMethodhook with the submitted result. - The
createPaymentMethodhook returns the persisted payment method shape.
The examples below are partial examples. They assume you have already initialized your payment provider SDK and mounted the provider payment element. The examples use Stripe, but the same pattern works with any payment provider.
The examples name the submitCreatePaymentMethod argument params, but they do not depend on it. Use the payment provider state available inside your iframe, such as the mounted provider element.
Submit create payment method
The submitCreatePaymentMethod function is called when the user selects the submit button in Root Dashboard or Embed. Use it to run the payment provider submission code in your collection module.
const renderCreatePaymentMethod = (params: {
application?: Record<string, any>;
policyholder?: Record<string, any>;
policy?: Record<string, any>;
}) => {
return `<!DOCTYPE html>
<html lang="en">
<head></head>
<body>
<div id="payment-element"></div>
<script>
const submitCreatePaymentMethod = (params) => {
return stripe.confirmSetup({
elements,
redirect: "if_required",
});
};
</script>
</body>
</html>`;
};
Complete create payment method
Within submitCreatePaymentMethod, call completeCreatePaymentMethod to pass the result from your payment provider code back to Root. Root then invokes the collection module's createPaymentMethod hook to finalise payment method creation.
Do not override
completeCreatePaymentMethod. Doing so will break the payment process.
const renderCreatePaymentMethod = (params: {
application?: Record<string, any>;
policyholder?: Record<string, any>;
policy?: Record<string, any>;
}) => {
return `<!DOCTYPE html>
<html lang="en">
<head></head>
<body>
<div id="payment-element"></div>
<script>
const submitCreatePaymentMethod = (params) => {
return stripe
.confirmSetup({
elements,
redirect: "if_required",
})
.then(function (result) {
// Pass the provider result to Root so it can call the createPaymentMethod hook.
return completeCreatePaymentMethod(result);
});
};
</script>
</body>
</html>`;
};Set loading state
The setIsLoading function controls the loading state while submitCreatePaymentMethod runs. Use it to reset the Root loading state after an error or when the provider submission flow completes.
Do not override
setIsLoading. Doing so will break the loading functionality.
const renderCreatePaymentMethod = (params: {
application?: Record<string, any>;
policyholder?: Record<string, any>;
policy?: Record<string, any>;
}) => {
return `<!DOCTYPE html>
<html lang="en">
<head></head>
<body>
<div id="payment-element"></div>
<script>
const submitCreatePaymentMethod = (params) => {
return stripe
.confirmSetup({
elements,
redirect: "if_required",
})
.then(function (result) {
if (result.error) {
setIsLoading(false);
}
return completeCreatePaymentMethod(result);
});
};
</script>
</body>
</html>`;
};Set validation state
The setIsValid function controls whether the submit button is enabled. Call setIsValid(false) while the form is incomplete, then call setIsValid(true) when the user can submit the payment method.
Do not override
setIsValid. Doing so will break the validation functionality.
const renderCreatePaymentMethod = (params: {
application?: Record<string, any>;
policyholder?: Record<string, any>;
policy?: Record<string, any>;
}) => {
return `<!DOCTYPE html>
<html lang="en">
<head></head>
<body>
<div id="payment-element"></div>
<script>
paymentElement.on("change", (event) => {
setIsValid(event.complete);
});
const submitCreatePaymentMethod = (params) => {
return stripe
.confirmSetup({
elements,
redirect: "if_required",
})
.then(function (result) {
if (result.error) {
setIsLoading(false);
}
return completeCreatePaymentMethod(result);
});
};
</script>
</body>
</html>`;
};Render payment method details
The renderViewPaymentMethod function creates a custom view for the payment method created through renderCreatePaymentMethod. Root displays this view on policy and application pages.
This component is optional. If you do not define it, Root displays the module data inside the payment method.
The renderViewPaymentMethod function accepts a single params object.
| Parameter | Type | Required | Description |
|---|---|---|---|
policy | Object | No | Used when the payment method view is for a policy object. |
application | Object | No | Used when the payment method view is for an application object. |
policyholder | Object | No | The policyholder assigned to the payment method, when available. Root Dashboard and Embed usually pass this value in current flows, but the hook contract allows it to be undefined. |
payment_method | Object | Yes | The collection module payment method object that the view displays. |
// Payment method view content to be returned in Root Dashboard.
const renderViewPaymentMethod = (params: {
application?: Record<string, any>;
policyholder?: Record<string, any>;
policy?: Record<string, any>;
payment_method: Record<string, any>;
}) => {
const { payment_method, policy } = params;
return `<!DOCTYPE html>
<html lang="en">
<head></head>
<body>
<table id="payment-details">
<tr>
<th>Type</th>
<td>Collection module</td>
</tr>
<tr>
<th class="no-background">Key</th>
<td class="key">${payment_method.collection_module_key}</td>
</tr>
<tr>
<th>Id</th>
<td>${payment_method.module.id}</td>
</tr>
<tr>
<th>Payment method</th>
<td>${payment_method.module.payment_method}</td>
</tr>
<tr>
<th>Billing day</th>
<td>${policy && policy.billing_day}</td>
</tr>
<tr>
<th>Livemode</th>
<td>${payment_method.module.livemode}</td>
</tr>
<tr>
<th>Status</th>
<td>${payment_method.module.status}</td>
</tr>
<tr>
<th>Usage</th>
<td>${payment_method.module.usage}</td>
</tr>
</table>
<img class="stripe-logo" />
</body>
</html>`;
};
Render payment method summary
The renderViewPaymentMethodSummary function creates a compact view for the payment method created through renderCreatePaymentMethod. Root displays this summary when a user opens the edit payment method view or creates a new payment method in Root Dashboard.
Use this component to show the existing payment method for the policyholder in a simplified card.
The renderViewPaymentMethodSummary function accepts a single params object.
| Parameter | Type | Required | Description |
|---|---|---|---|
policy | Object | No | Used when the payment method summary is for a policy. |
application | Object | No | Used when the payment method summary is for an application. |
policyholder | Object | No | The policyholder assigned to the payment method, when available. Root Dashboard and Embed usually pass this value in current flows, but the hook contract allows it to be undefined. |
payment_method | Object | Yes | The collection module payment method object that the summary displays. |
// Payment method summary content to be returned in Root Dashboard.
const renderViewPaymentMethodSummary = (params: {
application?: Record<string, any>;
policyholder?: Record<string, any>;
policy?: Record<string, any>;
payment_method: Record<string, any>;
}) => {
const { application, payment_method, policy, policyholder } = params;
return `<!DOCTYPE html>
<html lang="en">
<head></head>
<body>
<div id="payment-details">
<h3>Stripe payment method</h3>
<div id="card-details">
Card: ${payment_method.module.card?.brand || 'Unknown'} **** **** **** ${
payment_method.module.card?.last4 || 'Unknown'
}, Expires: ${payment_method.module.card?.exp_month || 'Unknown'}/${payment_method.module.card?.exp_year || 'Unknown'}
</div>
<div class="api-attributes-wrapper">
<div class="api-attributes" id="policy-id">Policy ID: ${policy && policy.policy_id}</div>
<div class="api-attributes" id="application-id">Application ID: ${
application && application.application_id
}</div>
<div class="api-attributes" id="policyholder-id">Policyholder ID: ${
policyholder && policyholder.policyholder_id
}</div>
</div>
</div>
</body>
</html>`;
};Troubleshooting
Submit button stays disabled
Confirm that your payment provider element calls setIsValid(true) when the form is complete. If setIsValid(false) is called and never reset, Root keeps the submit button disabled.
Loading state does not reset
Call setIsLoading(false) when the payment provider returns an error or when your submission flow ends without creating a payment method. Do not override Root's setIsLoading function.
Payment method is not created
Confirm that submitCreatePaymentMethod calls completeCreatePaymentMethod(result) with the provider result. Root uses this call to invoke the collection module's createPaymentMethod hook.
Iframe content does not render
Verify that each render function returns a complete HTML string with <html>, <head>, and <body> tags. Also check that the returned string does not contain syntax errors in the embedded script.
Updated 18 days ago