Widget Suite
A whole banking page in one component: a section menu over the widgets behind it, served by a single widget-init call.
Part ofEmbedded BankingandFinOps
A whole banking page in one component: a section menu over the widgets behind it, served by a single widget-init call. Unlike a widget, a suite owns the page it is placed on, so mount one per page.
Quick Start
import { WidgetSuite } from '@tesouro/embedded-components-react';
export function BankingPage() {
return (
<WidgetSuite
baseUrl="https://api.tesouro.com"
widgetToken={widgetToken}
organizationId={organizationId}
/>
);
}sections defaults to WIDGET_SUITE_DEFAULT_SECTIONS, the full surface in menu order. Pass a list to narrow or reorder it, for example sections={['dashboard', 'accounts', 'cards']}.
Behaviour
- A section you list is still hidden when the user's token doesn't earn it, so
sectionsis a ceiling, not a promise of what renders. - Before the menu paints, the suite shows placeholders while loading, a retry state if widget init fails, the disclosure acceptance surface when the session owes the bank's disclosures, full-screen onboarding whenever the onboarding widget has something to show for the organization's application (the form, or its status card with a Check again button), or a "We can't show your application" retry state when it has nothing to show (a denial more than 30 days old, or an unrecognized status). An invited teammate goes straight to the disclosure gate.
- When onboarding completes, the suite switches to the menu on its own, without a reload.
- The composed widgets inherit the suite's auth, organization and query cache, so the whole page makes one widget-init call.
- Only the open section is addressable. To deep-link an account, card or settings tab, mount that widget directly instead.
- Passing
sectionwithoutonSectionChangefreezes the menu. - When the token doesn't earn the section you asked for, the suite silently shows the first section the user can see and doesn't call
onSectionChange. - The Dashboard's balance rows and CTAs change section like a menu click and are reported through
onSectionChange. - In Cards, the debit Create card action shows only when the token holds the issue, roster and funding scopes.
- The suite takes no data or loading props. Those belong to the widgets it mounts.
Sections
| Section id | What it mounts |
|---|---|
dashboard | Balances and Insights side by side |
accounts | BankAccountsWidget |
cards | CreditCardsWidget and DebitCardsWidget, per program the token reads |
transfers | TransfersWidget |
bill-pay | BillPayWidget |
invoicing | ReceivablesWidget |
expenses | a placeholder, until the expenses surface is ready |
settings | SettingsWidget, which resolves its own sections from the same scopes |
Props
Widget props
| Prop | Type | Default | Description |
|---|---|---|---|
sections | readonly WidgetSuiteSectionId[] | WIDGET_SUITE_DEFAULT_SECTIONS | Which sections the suite offers, in menu order. A listed section is still hidden when the token doesn't earn it. |
sectionControlled | WidgetSuiteSectionId | undefined | Which section is showing. Supplying it makes the menu controlled for the lifetime of the mount, so pair it with onSectionChange. |
defaultSectionUncontrolled | WidgetSuiteSectionId | first of sections | Which section the suite opens on. Read once per mount, and ignored when section is supplied. |
onSectionChangeEvent | (section) => void | undefined | Called when the user moves the suite. Never fired on mount or for the entitlement fallback. |
showSectionTitle | boolean | true | Shows a heading above each section, named as its menu item is. Set false when your page already heads the suite. |
onboardingDisclosureLinks | DisclosureLinks | undefined | Legal disclosure URLs for the onboarding agreement step, shown when the organization has no application yet. Omitted fields render as non-clickable text. |
cardArtSrc | string | undefined | Card artwork URL for the debit Create card sheet and card face; omitted, a neutral plastic and the bank logo are used. Credit Create card is always hidden. |
Label overrides
| Prop | Type | Default | Description |
|---|---|---|---|
labelsLabels | WidgetSuiteLabelOverrides | WIDGET_SUITE_LABELS_EN | Every string on the page in one tree, including the copy of each section's widget. Override any leaf and its siblings keep their defaults. |
Examples
Section in the URL
Pass section and onSectionChange together to own navigation. Use defaultSection instead when you only need to choose where the suite opens.
'use client';
import { useRouter, useSearchParams } from 'next/navigation';
import {
WidgetSuite,
WIDGET_SUITE_DEFAULT_SECTIONS,
type WidgetSuiteSectionId,
} from '@tesouro/embedded-components-react';
function toSection(value: string | null): WidgetSuiteSectionId | undefined {
const known: readonly string[] = WIDGET_SUITE_DEFAULT_SECTIONS;
return value && known.includes(value)
? (value as WidgetSuiteSectionId)
: undefined;
}
export function BankingPage() {
const router = useRouter();
const params = useSearchParams();
return (
<WidgetSuite
section={toSection(params.get('page')) ?? 'dashboard'}
onSectionChange={(next) => router.replace(`?page=${next}`)}
/>
);
}Never pass section={undefined} while controlling the suite: that hands control back to it. router.replace keeps Back from stepping through every section visited.
Labels
A group under sections takes the same label props as the widget behind it. providerLabels is separate.
<WidgetSuite
labels={{
menu: { accounts: 'Bank accounts' },
sectionTitle: { bankTagline: '{bankName} holds your deposits' },
sections: {
cards: { creditCards: { labels: { emptyTitle: 'No credit cards yet' } } },
},
}}
/>See the exported WidgetSuiteLabels type for every key, and WIDGET_SUITE_LABELS_EN for the defaults.
TypeScript
import type {
WidgetSuiteProps,
WidgetSuiteSectionId,
WidgetSuiteLabels,
WidgetSuiteLabelOverrides,
} from '@tesouro/embedded-components-react';Each label group is also exported under its own name (for example WidgetSuiteMenuLabels and WidgetSuiteCardsLabels).