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 sections is 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 section without onSectionChange freezes 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 idWhat it mounts
dashboardBalances and Insights side by side
accountsBankAccountsWidget
cardsCreditCardsWidget and DebitCardsWidget, per program the token reads
transfersTransfersWidget
bill-payBillPayWidget
invoicingReceivablesWidget
expensesa placeholder, until the expenses surface is ready
settingsSettingsWidget, which resolves its own sections from the same scopes

Props

Widget props

PropTypeDefaultDescription
sectionsreadonly WidgetSuiteSectionId[]WIDGET_SUITE_DEFAULT_SECTIONSWhich sections the suite offers, in menu order. A listed section is still hidden when the token doesn't earn it.
sectionControlledWidgetSuiteSectionIdundefinedWhich section is showing. Supplying it makes the menu controlled for the lifetime of the mount, so pair it with onSectionChange.
defaultSectionUncontrolledWidgetSuiteSectionIdfirst of sectionsWhich section the suite opens on. Read once per mount, and ignored when section is supplied.
onSectionChangeEvent(section) => voidundefinedCalled when the user moves the suite. Never fired on mount or for the entitlement fallback.
showSectionTitlebooleantrueShows a heading above each section, named as its menu item is. Set false when your page already heads the suite.
onboardingDisclosureLinksDisclosureLinksundefinedLegal disclosure URLs for the onboarding agreement step, shown when the organization has no application yet. Omitted fields render as non-clickable text.
cardArtSrcstringundefinedCard 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
PropTypeDefaultDescription
labelsLabelsWidgetSuiteLabelOverridesWIDGET_SUITE_LABELS_ENEvery 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).

On this page