Bank UI Kit

The Flutter front-end for digital banking.

Every surface a retail, Islamic, or business bank ships, from onboarding to servicing, as composable Flutter widgets. One codebase, four built-in themes, your backend.

CI OpenSSF Scorecard pub package License: MIT Flutter style: flutter_lints

173 components · 23 modules · 4 built-in themes · WCAG 2.1 AA gates enforced in CI · RTL + Arabic-Indic numerals

▶ Try the live demo

Browse every component and the full Meridian flagship app in your browser: switch themes, dark mode, and RTL live.


Heritage Studio Voltage Bloom
Heritage preset Studio preset Voltage preset Bloom preset

The same widgets in four built-in themes, so rebranding takes minutes.


Contents

Evaluating it

Building with it


What it is

A component library, not a screen template. You compose the widgets into an app you already own rather than copying whole screens out of a starter project. The kit covers accounts, payments, cards, onboarding and KYC, PFM and insights, lending, rewards, Islamic banking, business-banking approvals, disputes, secure messaging, and statements: 173 components across 23 modules, benchmarked against 21 of the world's leading banking apps.

It is backend-agnostic by construction. Data goes in through constructors, events come out through callbacks, and nothing in lib/ opens a network connection, writes to disk, or depends on a state-management package. The headless flow controllers are ChangeNotifier state machines that own step state and nothing else. Your core banking APIs stay yours.

Everything visible is a token. Colour, shape, depth, motion, and numeral typography come from BankThemeData and BankTokens, which are generated from a platform-neutral token file and serialise back to JSON. That is what makes a rebrand a constructor argument instead of a fork.


Enterprise readiness

The questions below are the ones that come up at bank and agency intake, in roughly the order they get asked. Each answer links to the document or the workflow file that carries the evidence, so you can check the claim rather than take it.

Question at intake Where this project stands Evidence
Is there an accessibility conformance report? Yes. WCAG 2.1 A and AA plus EN 301 549 V3.2.1, per component, with the gaps named rather than smoothed over. Self-assessed, not third-party audited, and it says so on its first page ACR · openacr.yaml
Is accessibility tested, or only asserted? Enforced in CI. A contrast gate across every preset in light and dark, a 44 px tap-target gate, an accessible-label gate, and golden regression across preset, brightness, and direction. A failure breaks the build ci.yml · test/accessibility_*_test.dart
Who carries the regulatory obligation? The bank does. The kit implements the UX pattern; the regulated control behind it stays yours. The split is written down line by line compliance matrix
Can you produce an SBOM? On every commit and every release, in SPDX 2.3 and CycloneDX 1.6 from one resolution, scanned against OSV, and byte-reproducible from the commit plus the lockfile shipped with it supply chain · sbom.yml
Is the release chain attested? Publishing runs over OIDC with no stored credential, bound to a tag ref. Release artifacts carry a Sigstore-backed SLSA build provenance attestation. Every GitHub Action is pinned by commit SHA release.yml · publish.yml
Is there a published OpenSSF Scorecard? Yes, refreshed weekly and on branch-protection changes, with the SARIF kept as a build artifact Scorecard viewer · scorecard.yml
What can change under us, and with how much warning? A written dependency contract: what counts as breaking for a UI kit including default visual values, the deprecation window, pinning guidance, and the 1.0 gate with the status of each criterion stability and support
What happens if the project stops? One maintainer today, stated plainly. MIT, no private infrastructure, vendorable as a path dependency, and the design tokens are portable JSON that outlive the Dart code stability and support, continuity section · GOVERNANCE.md
How do we report a vulnerability? Private GitHub advisory or email, with severity clocks adjusted for a UI library, where on-screen leakage of financial data is treated one band higher than raw CVSS SECURITY.md
Does it work in our markets? RTL-first on every widget, four numeral scripts, locale-aware money for every currency the kit knows, and Hijri calendar support localization and RTL

Where this project is honest about its gaps

It is version 0.3.0, which means pre-1.0 minors are permitted to break you, so pin exactly. It has one maintainer, so the bus factor is one. The accessibility report is a self-assessment and no independent firm has audited it. Those facts are why the documents above exist, and each document names the mitigation available to an adopter rather than an aspiration.

The enterprise documentation set

stability and support · versioning and releases · supply chain · compliance matrix · accessibility conformance · ACR · design tokens · integration playbook · white-label guide · localization and RTL

How it compares

Bank UI Kit Typical screen-template kits
Integration model Compose into any existing app Copy-paste whole screens
Design tokens Platform-neutral W3C DTCG tokens.json generates the Dart tokens (CI-enforced) + toJson/fromJson for Figma and remote branding Hard-coded values
Theming 4 presets + fully custom themes, runtime-switchable Fork the package
RTL support First-class, every widget Mirror-on-demand or none
Localization Locale-aware money (German 1.234,56, French 1 234,56, Indian lakh) + 4 numeral scripts + Hijri calendar English only
Accessibility WCAG 2.1 AA enforced in CI: contrast gate across every preset, tap-target and label gates, semantics Not specified
Conformance evidence Published ACR (WCAG 2.1 AA, EN 301 549) + machine-readable OpenACR None
Supply chain SBOM on every commit, OSV scan, SLSA provenance, published Scorecard None
Visual regression Golden tests pin every preset × light/dark None
State management Agnostic (pure props + callbacks) Tied to the template's choice
Money Lossless Decimal-backed Money type double
Tests 487 unit, widget, golden, and accessibility test cases None

Design tokens: one source, every consumer

The tokens are not Dart constants that only Flutter can read. The source of truth is a platform-neutral W3C DTCG file, tokens/design-tokens.json, that generates the Dart tokens, and CI fails if the two drift:

// tokens/design-tokens.json  →  generates lib/src/theme/tokens.dart
"color":  { "positiveBalance": { "$type": "color", "$value": "#047857" } },
"space":  { "4": { "$type": "dimension", "$value": "16px" } },
"radius": { "full": { "$type": "dimension", "$value": "999px" } }
dart run tool/generate_tokens.dart          # regenerate tokens.dart from JSON
dart run tool/generate_tokens.dart --check   # CI drift guard

And any brand round-trips to and from JSON. These are the same tokens a Figma library or an iOS/Android app would consume, or that a server could deliver for remote re-branding:

final json = BankPreset.heritage.apply(base).extension<BankThemeData>()!.toJson();
// → { "colors": { "primary": "#006341FF", ... }, "radius": {...}, ... }
final brand = BankThemeData.fromJson(json);   // lossless round-trip

All four presets are exported to tokens/themes/ as Figma-Variables-ready token sets. The same source feeds Flutter, Figma, and native apps, which is what makes this a design system rather than only a widget library. It is also the reason your design decisions survive independently of this package: those files carry no dependency on Flutter, on Dart, or on the kit. Full pipeline in doc/enterprise/design-tokens.md.

One token change rebrands every surface

Design tokens flow into four presets, into 173 components, into your app

Tokens set colour, shape, depth, and numeral typography once. Presets are just token sets: swap one and every component follows, light and dark, LTR and RTL. Your rebrand is a single constructor argument rather than a multi-quarter project.


Accessibility, enforced in CI

Accessibility here is a build gate, not a section in a sales deck. Every push runs:

  • a WCAG contrast test (92 cases) covering every text pair and financial colour across all four presets in light and dark;
  • tap-target (44 px) and accessible-label guideline checks on interactive widgets;
  • golden visual-regression across preset × brightness × direction.

The conformance position, including what is verified, what is the host app's responsibility, and what is still a gap with a remediation date, is written down in doc/enterprise/accessibility-conformance.md. The formal report a procurement team files is the ACR, with a machine-readable OpenACR source of truth beside it.

Both are self-assessments. No independent accessibility firm has assessed this package, and neither document pretends otherwise.

Regenerate goldens with flutter test --update-goldens.


Supply chain and provenance

Every commit and every release produces a Software Bill of Materials in both SPDX 2.3 and CycloneDX 1.6, generated from one dependency resolution so the two formats cannot disagree. The generator derives its timestamps from the commit rather than the clock, and ships the resolved pubspec.lock inside the artifact, so re-running it on the same commit gives byte-identical documents. The same document is scanned against OSV, and a known advisory affecting a runtime dependency fails the build.

Releases publish to pub.dev over OIDC through Dart's trusted-publishing workflow, with no credential stored in the repository or in Actions secrets, and the artifacts attached to each GitHub Release carry a Sigstore-backed SLSA build provenance attestation. Every third-party GitHub Action is pinned by commit SHA rather than by tag.

Details, and how to verify any of it yourself, are in doc/enterprise/supply-chain.md.


Stability: what can change under you

The package is at 0.3.0. Under SemVer a 0.x minor may break you, so pin exactly until 1.0:

dependencies:
  bank_ui_kit: 0.3.0   # exact, no caret, while the package is pre-1.0

For a UI kit the interesting breakage is not a deleted method. It is a default colour, size, elevation, font, or motion value moving, which changes what ships to customers without a single analyzer warning and fails your own golden tests. This project treats those as breaking changes and says so. The stability and support policy lists them item by item, and names the three releases that have already changed visual defaults.

The rest of the dependency contract, including the deprecation window, the procedure for retiring a visual default, the supported-version policy, the 1.0 criteria with the current status of each, and the continuity story for a single-maintainer project, is in doc/enterprise/stability-and-support.md. Release mechanics and the roadmap are in doc/enterprise/versioning-and-releases.md.


Install

dependencies:
  bank_ui_kit: 0.3.0   # exact, no caret, while the package is pre-1.0

Or take it straight from git, which is also the vendoring path if you mirror the repository into internal hosting:

dependencies:
  bank_ui_kit:
    git:
      url: https://github.com/sayed3li97/bank-ui-kit.git
      ref: v0.3.0

Pin exactly either way until 1.0, and read what can change under you before you take the upgrade.

Import only the modules you use:

import 'package:bank_ui_kit/core.dart';       // accounts, transactions, transfers, cards, auth, states, insights…
import 'package:bank_ui_kit/saving.dart';     // pots, round-ups, income sorter
import 'package:bank_ui_kit/social.dart';     // joint accounts, shared goals, peer payments
import 'package:bank_ui_kit/investing.dart';  // wallets, holdings, buy/sell, charts
import 'package:bank_ui_kit/credit.dart';     // installments, credit gauges, subscriptions, perks

Quick start

Wrap your app in a BankUiScope and apply a preset to your ThemeData:

import 'package:bank_ui_kit/core.dart';
import 'package:flutter/material.dart';

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return BankUiScope(
      initialData: const BankUiScopeData(preset: BankPreset.studio),
      child: MaterialApp(
        theme: BankPreset.studio.apply(ThemeData.light(useMaterial3: true)),
        darkTheme: BankPreset.studio.apply(ThemeData.dark(useMaterial3: true)),
        home: const Dashboard(),
      ),
    );
  }
}

Then compose with the widgets:

BankBalanceText(money: account.balance, size: BankBalanceSize.hero),
BankVirtualCardWidget(account: account, cardholderName: 'ALEX MORGAN'),
BankTransactionListTile(transaction: tx, onTap: () { /* open detail */ }),

Design presets

Four first-class presets ship in the box. Each defines a complete BankThemeData (colours, shape radii, elevation/glow, brand font, numeral typography) in light and dark.

Preset Personality Signature
Studio Restrained, editorial Petrol-green, soft-shadow depth, Space Grotesk
Voltage Electric, dark-native Violet→cyan gradient, pill shapes, glow depth
Bloom Warm, consumer-friendly Coral primary, fully-rounded, Nunito
Heritage Institutional, Islamic-banking ready Deep forest green + muted gold, pairs with BankShariahBadge and profit-rate labels

Switch presets at runtime by changing the ThemeData you pass to MaterialApp. Every widget re-themes itself because it reads tokens from BankThemeData.of(context).

Accounts · Studio Accounts · Voltage Accounts · Bloom

Heritage: the Islamic-banking preset

A complete demo app (HeritageDashboard in the example) built on the Heritage preset: SAR balances, profit-rate labels via islamicFinanceMode, BankShariahBadge on eligible products, and gold-accent virtual cards.

Heritage · light Heritage · dark Home · Heritage

Every component is also captured under all four presets: see doc/screenshots/components/ (Studio at the top level, plus heritage/, voltage/, and bloom/ sub-folders for theme-specific decks).


Custom themes

Not limited to the four presets: build a fully custom theme from your brand colour. Only primary and brightness are required; every other token has a sensible default.

final myTheme = BankThemeData.custom(
  primary: const Color(0xFF0052CC),
  brightness: Brightness.light,
  // optionally override any token:
  cardRadius: const BorderRadius.all(Radius.circular(20)),
  useGlow: true,
  glowColor: const Color(0x440052CC),
  accentGradient: const LinearGradient(
    colors: [Color(0xFF0052CC), Color(0xFF00B8D9)],
  ),
);

MaterialApp(
  theme: ThemeData.light(useMaterial3: true).withBankTheme(myTheme),
  darkTheme: ThemeData.dark(useMaterial3: true).withBankTheme(
    BankThemeData.custom(
      primary: const Color(0xFF4D9DFF),
      brightness: Brightness.dark,
    ),
  ),
);

withBankTheme() registers the theme extension and synchronises the Material ColorScheme, so Material widgets and Bank UI Kit widgets stay consistent.

You can also start from a preset and override just the fields that differ:

final tweaked = BankPreset.bloom
    .apply(ThemeData.light(useMaterial3: true))
    .extension<BankThemeData>()!
    .copyWith(primary: const Color(0xFFE91E63));

The flagship app: a complete product suite

The kit ships with Meridian, a full reference banking app built entirely from Bank UI Kit widgets: a real product catalogue (accounts, cards, loans, mortgages, investments, protection), product detail pages with a conventional/Shariah toggle, an end-to-end lending application, and a servicing view with a live application tracker. It is the app a bank CEO reviews before signing off a launch: every rate, disclosure, and representative example is presented the way a regulator expects.

Run it in any of the four presets:

cd example
flutter run -t lib/flagship_main.dart      # switch BankPreset in flagship_main.dart

The Auto Finance application, end to end

One BankApplicationController drives seven steps; each step is a real kit widget. This is the actual journey, captured stage by stage from the running app:

The Auto Finance apply journey: eligibility, customise, offer, documents, disclosures, e-signature, approval

Eligibility (soft search, no credit impact) → customise amount and term → firm personalised offer with the representative example → document capture → pre-contract disclosures and consents → e-signature → approval with a reference and funding timeline.

The product suite

Home Explore catalogue Product detail
Meridian home with total position, accounts, and a pre-qualified offer Product catalogue with category grid, featured Auto Finance, and the loans line-up Auto Finance product detail with a conventional and Shariah toggle
Apply: your offer My products Shariah variant (Heritage)
A firm, personalised credit offer with the full cost breakdown Servicing view: holdings, a live application tracker, and relationship summary The same product detail in the Heritage Islamic-banking preset

Every product line in the app maps to a documented, regulator-aware pattern. The complete banking-products reference (lending, deposits, cards, wealth, insurance, and their Islamic variants, with the metrics, journeys, and servicing views each one needs) lives in doc/research/banking-products.md.


Journeys, not just widgets

Components are designed to chain into complete, compliant banking journeys. Below, a payment travels through five kit widgets while one headless controller owns the state machine:

A payment journey composed from kit components over one headless flow controller

The same composition pattern covers every core journey. The full catalogue of 25 journey blueprints (triggers, steps, variants, error states) lives in doc/banking-journeys.md.

Journey Chain of kit components
Onboard a customer BankOnboardingCarouselBankStepProgressIndicatorBankDocumentCaptureOverlayBankLivenessCheckOverlayBankAsyncVerificationStateBankSuccessAnimation
Pay a bill BankBillForecastListBankBillPayTileBankAmountInputFieldBankTransferReviewCardBankScaApprovalSheetBankReceiptView
Send money to a friend BankBeneficiaryPickerBankAmountKeypadBankTransferReviewCardBankTransactionPinSheetBankTransferResultScreen
Recover a lost card BankPanicFreezeButtonBankCardControlsPanelBankDisposableCardTileBankPhysicalCardMaterialPickerBankStatusTracker
Grow savings BankFinancialHealthScoreBankSavingsPotCardBankRoundUpSettingsSheetBankSavingsChallengeCardBankSharedPotInvite
Dispute a charge BankTransactionDetailSheetBankDisputeWizardSheetBankSecureMessageThreadBankStatusTrackerBankInAppNotificationCenter

Component catalogue

173 widgets across 23 modules. Each screenshot below is a live render of that module's showcase screen (Studio preset, light mode) from the example app.

For the full parameter-level API reference (every constructor argument, type, required/optional status, and default value) see doc/component-reference.md.

States & feedback

BankSkeletonLoader · BankEmptyStateView · BankErrorStateView · BankSuccessAnimation · BankToastBanner · BankFraudAlertBanner · BankAppGateScreen (11 gate reasons: maintenance, force update, root/VPN blocks, waiting room) · BankConnectivityBanner · BankServiceStatusList · BankUpdatePromptSheet

Accounts & balances

BankAccountCard · BankAccountSwitcher · BankBalanceText (privacy-aware) · BankProductItemTile · BankAccountNumberText · BankPeekBalance (pre-login peek) · BankEarlyPaydayCard

Transactions

BankTransactionListTile · BankTransactionGroupHeader · BankTransactionDetailSheet · BankTransactionFilterSheet · BankReceiptView · BankTransactionCostSplitSheet · BankTransactionCategorySplitSheet


Transactions Transfers Cards

Transfers & payments: BankAmountKeypad · BankBeneficiaryPicker · BankTransferReviewCard · BankTransactionPinSheet · BankScheduledTransferToggle · BankPaymentRequestCard · BankTransferResultScreen · BankContactPaymentSheet

Cards: BankFlipCard · BankHorizontalAccountCard · BankVirtualCardWidget (flat / gradient / mesh / metallic / image) · BankCardControlsPanel · BankCardPinManager · BankPhysicalCardMaterialPicker · BankDisposableCardTile (single-use) · BankMerchantBlockList (self-exclusion) · BankFamilyCardTile (teen cards)

Flip cards

Smooth 3-D perspective flip animation revealing the account details on the back face. Three trigger modes, two flip axes, three front-face layouts, and three background modes ship in the box: all backward-compatible and opt-in.

Cards · Studio Cards · Voltage Cards · Bloom

BankFlipCard: generic flip container

Wraps any two widgets in a perspective flip. Use it for any two-sided surface.

BankFlipCard(
  trigger: BankFlipTrigger.tapToFlip,  // tapToFlip · builtInButton · external
  flipAxis: BankFlipAxis.horizontal,   // horizontal (Y-axis) · vertical (X-axis)
  flipDuration: const Duration(milliseconds: 400),
  flipCurve: Curves.easeInOutCubic,
  frontBuilder: (ctx, _) => MyFront(),
  backBuilder:  (ctx, _) => MyBack(),
)

BankHorizontalAccountCard: landscape account card with flip

A landscape-format bank card showing balance, masked number, and account-type icon on the front. The back reveals the full IBAN / account number and sort code / BIC with tap-to-copy actions.

BankHorizontalAccountCard(
  account: myAccount,
  cardholderName: 'Alice Johnson',
  // Front-face layout
  layout: BankHorizontalCardLayout.centred,        // balanceLeft · centred · balanceBottom
  // Background
  background: BankHorizontalCardBackground.image,  // themeGradient · solidColor · image
  backgroundImage: const AssetImage('assets/card_bg.jpg'),
  backgroundImageOverlay: Colors.black54,
  // Flip
  trigger: BankFlipTrigger.builtInButton,
  flipAxis: BankFlipAxis.horizontal,
)

External (host-controlled) flip: pair isFlipped with onFlip:

bool _flipped = false;

BankHorizontalAccountCard(
  account: myAccount,
  trigger: BankFlipTrigger.external,
  isFlipped: _flipped,
  onFlip: () => setState(() => _flipped = !_flipped),
)

Enhanced BankVirtualCardWidget

The existing virtual-card widget now accepts an image background and an explicit flip trigger. All new parameters are optional: existing code compiles unchanged.

BankVirtualCardWidget(
  account: account,
  cardholderName: 'ALEX MORGAN',
  // new: image background
  backgroundImage: const NetworkImage('https://example.com/card.jpg'),
  // new: flip trigger (default: tapToFlip: same as before)
  flipTrigger: BankFlipTrigger.builtInButton,
  // new: optional custom flip button
  flipButtonBuilder: (ctx, flip) => IconButton(
    icon: const Icon(Icons.flip),
    onPressed: flip,
  ),
)
Auth & security Onboarding & KYC Saving

Auth & security: BankPinKeypad · BankPinDots · BankBiometricPromptButton · BankPrivacyToggle · BankDeviceTrustBanner · BankSessionTimeoutDialog · BankAppSwitcherPrivacyOverlay · BankOtpInput · BankScaApprovalSheet (PSD2 dynamic linking) · BankDeviceSessionTile · BankCallVerificationScreen (anti-vishing) · BankEidLoginButton (national eID) · BankPanicFreezeButton

Onboarding & KYC: BankStepProgressIndicator · BankDocumentCaptureOverlay · BankLivenessCheckOverlay · BankAsyncVerificationState · BankConsentModal · BankConsentManagementList (open-banking dashboard) · BankOnboardingCarousel · BankAddressForm

Saving: BankSavingsPotCard · BankRoundUpSettingsSheet · BankPotContributionSheet · BankIncomeSorterSheet · BankSharedPotInvite · BankSavingsChallengeCard (streaks + stamps) · BankSavingsProjectionCard (earnings calculator)

Social Investing Credit

Social: BankJointTransactionListTile · BankAccountOwnershipBadge · BankSharedGoalProgressCard · BankMoneyCircleCard (Jamiyah saving circle)

Investing: BankPortfolioPerformanceChart · BankHoldingsListTile · BankWatchlistCard · BankBuySellSheet · BankAssetPriceTicker · BankLiveExchangeConverter · BankCurrencyWalletTabBar

Credit: BankCreditLimitGauge · BankFlexEligibleBadge · BankInstallmentPlanSelector · BankRepaymentScheduleView · BankCreditScoreGauge · BankLoanCalculatorCard · BankCreditLimitAdjuster (user-set limit) · BankPreapprovedLoanCard · BankOverdraftCushionMeter

Subscriptions Insights Notifications

Subscriptions: BankPlanComparisonTable · BankPaywallSheet · BankPerksMarketplaceCard · BankReferralInviteCard

Insights: BankSpendingBreakdownChart (donut) · BankBudgetGaugeWidget · BankInsightCard · BankCashflowChart (history + forecast) · BankRecurringMerchantTile (subscription detection) · BankFinancialHealthScore · BankFoundMoneyList

Notifications: BankInAppNotificationCenter · BankAlertPreferencesPanel

Forms & input

BankTextField · BankAmountInputField (currency-aware) · BankMaskedInputField (IBAN / PAN / sort code, mod-97 + Luhn) · BankPhoneInputField (E.164) · BankCountryPicker (236 countries) · BankPeriodSelector

Payments & billing

BankBillPayTile + BankBillCalendarStrip · BankStandingOrderTile · BankTransferLimitManager (SCA-gated) · BankQrScannerOverlay + BankMyQrCard (local QR encoding) · BankBillForecastList (bill prediction) · BankAtmLocatorTile + BankCardlessCashCode

Products & applications

The origination surface behind the flagship app: market a product, check eligibility, present an offer, and take an application to signature.

Product card Personalised offer Eligibility result

BankProductCard (rate hero, features, badges, dual CTA) · BankProductCategoryTile (catalogue grid) · BankEligibilityResultCard (soft-search outcome, no credit impact) · BankOfferSummaryCard (firm/indicative offer with the representative example) · BankRatioGauge (LTV / DTI / LTI affordability bands) · BankDisclosureConsentSheet (pre-contract disclosures + no-dark-pattern consents) · BankESignaturePad (typed or drawn, timestamped) · headless BankApplicationController (the seven-step state machine)

Rewards & engagement

BankPointsHubCard (earn/burn) · BankOffersRail (card-linked offers) · BankCashbackCategoryPicker (quarterly picks) · BankStoriesCarousel (stories + full-screen viewer) · BankPrizeDrawCard (prize-linked savings)

Islamic banking

BankZakatCalculator (nisab-aware) · BankDonationHubCard (verified charities) · BankShariahBadge · profit-rate labeling via islamicFinanceMode · Murabaha cost-plus math in BankLoanCalculatorCard · the Heritage preset

The Zakat calculator applies the widely used 2.5% rate on zakatable wealth above a bank-supplied nisab threshold; the calculation method, threshold, and the charity verification flag are inputs your Shariah board controls, not rulings the kit makes.

Business banking

BankApprovalRequestTile (maker-checker) · BankBatchPaymentReviewSheet · BankValueDiffRow

Documents & deposits

BankStatementListTile · BankChequeCaptureOverlay + BankChequeDepositSummary (remote deposit capture)

Support & servicing

BankDisputeWizardSheet (+ headless BankDisputeFlowController) · BankSecureMessageThread · BankHelpFaqList · BankAssistantPanel (named AI assistant entry)

Scaffolding & display

BankAppBar · BankBottomNavBar · BankEmblem · BankSummaryStack · BankStatusTracker · BankQuickActionsGrid · BankMoneyProtectionBanner · BankShariahBadge · BankWalletProvisioningButton · BankTravelNoticeForm


Cross-cutting features

Privacy mode

BankPrivacyToggle flips BankUiScope.privacyEnabled; every BankBalanceText masks itself automatically.

BankBalanceText(money: account.balance) // shows '••••' when privacy is on

BankAppSwitcherPrivacyOverlay blurs the app-switcher snapshot at the widget level. It is defense in depth, not capture protection: pair it with platform FLAG_SECURE (Android) and screen-capture protection (iOS) per the recipes in doc/enterprise/integration-playbook.md.

Currency-correct money display

Every amount renders through a currency engine that knows each currency's official symbol, minor units, and symbol placement: the Saudi riyal symbol, three-decimal Gulf currencies (OMR, KWD, BHD), zero-decimal JPY/KRW, and crypto precision all follow their own guidelines. Register your own with BankCurrencies.register.

BankBalanceText(money: Money.fromDouble(1250.5, 'OMR')) // ر.ع. 1,250.500

Grouping and separators are locale-aware: kit money widgets read the ambient Localizations locale, so the same amount reads correctly in every market. Calling the formatter yourself? Pass context.bankLocale.

BankMoneyFormatter.format(amount: a, currencyCode: 'EUR', locale: 'de'); // €1.234.567,89
BankMoneyFormatter.format(amount: a, currencyCode: 'EUR', locale: 'fr'); // €1 234 567,89
BankMoneyFormatter.format(amount: a, currencyCode: 'INR', locale: 'en_IN'); // ₹12,34,567.89

Numeral styles

Four numeral scripts, independent of locale (grouping) and useful for GCC and South-Asian apps: Western, Eastern Arabic-Indic (٠١٢), Persian (۰۱۲), and Devanagari (०१२). The kit bundles Noto fallback fonts (kBankFontFallback) so currency symbols (₹ ₩ ₫ ₿ Ξ), Arabic script, and these numerals render everywhere: offline, on web without a CDN, and on devices lacking those system fonts.

BankUiScope(
  initialData: BankUiScopeData(numeralStyle: NumeralStyle.easternArabicIndic),
  child: ...,
)

Islamic finance mode

Swaps interest/APR labels for profit-rate equivalents wherever a widget renders label text.

BankUiScope(initialData: BankUiScopeData(islamicFinanceMode: true), child: ...)

Localization

Locale-aware number formatting (above) plus injectable copy: ships English strings and overrides any subset via BankUiStrings. The full position, including what the kit does not translate for you, is in doc/enterprise/localization-and-rtl.md.

RTL

Every widget is built RTL-first with directional geometry throughout; widget-test coverage runs under TextDirection.rtl, and an LTR/RTL golden test pins the mirrored layout so it can't regress.

Air-gapped and offline builds

Widgets that take an image URL resolve it through BankUiScopeData.imageResolver when one is set, so a deployment with no outbound network can supply its own ImageProvider (asset, cache, or internal CDN) without touching kit source. Fonts are bundled, not fetched, so the numeral scripts and currency glyphs render with no CDN.

Accessibility

See Accessibility, enforced in CI above for the gates, and the ACR for the per-component conformance position.


Architecture and principles

  • Widgets read colours, radii, spacing, elevation, and numeral typography from BankThemeData / BankTokens, never from hard-coded values. The scalar tokens are generated from a W3C DTCG tokens.json (CI-enforced), and any brand serialises to and from JSON. See Design tokens: one source, every consumer.
  • Widgets are state-management agnostic: data comes in via the constructor and events go out via callbacks, with no provider/bloc/riverpod coupling in lib/.
  • The Money type wraps Decimal, so no double ever touches an amount.
  • The headless flow controllers BankKycFlowController, BankTransferFlowController, BankIncomeSorterController, BankApplicationController, and BankDisputeFlowController own multi-step flow state so you can swap the visual layer.
  • Widgets expose Widget? illustration slots and the kit bundles no raster/vector art, so you bring your own imagery.
lib/
  core.dart · saving.dart · social.dart · investing.dart · credit.dart   # barrels
  src/
    theme/      # BankTokens, BankThemeData, presets, custom theming
    scope/      # BankUiScope + BankUiStrings
    models/     # Money, Transaction, BankAccount, …  (==, hashCode, copyWith)
    <feature>/  # one folder per module
    controllers/# headless flow controllers

Running the example

The example app ships two entry points:

Entry point Launch command What it shows
Component gallery flutter run -t lib/gallery_main.dart Every component with live parameter controls, preset/dark-mode switching, and search
Demo dashboard flutter run Revolut-style demo app under the Studio preset
cd example
flutter pub get
flutter run -t lib/gallery_main.dart    # interactive gallery
flutter run                             # demo dashboard

Regenerating the screenshots

Screenshots in this README are produced from the real widgets via Flutter web:

cd example
flutter build web -t lib/screenshot_harness.dart --release --no-web-resources-cdn --no-tree-shake-icons
cd ..
node tool/screenshots.mjs          # requires playwright + a Chromium
node tool/walkthrough.mjs           # rebuilds the flagship apply-journey GIF

Try it, then build with it

Run the gallery and switch presets live:

git clone https://github.com/sayed3li97/bank-ui-kit.git
cd bank-ui-kit/example && flutter run -t lib/gallery_main.dart

Building a bank? Start from the journey blueprints, compose the widgets, wire your APIs to the callbacks, and read the integration playbook. Your core banking stays yours.


Contributing

See CONTRIBUTING.md and our Code of Conduct. In short: flutter analyze and flutter test must be green, and every change must work across all four presets, both brightnesses, and RTL. How changes are reviewed and who decides is in GOVERNANCE.md.


License

MIT © 2026 Sayed Ali and Bank UI Kit contributors.

Fonts bundled with the kit: Space Grotesk, Fredoka, and Nunito are licensed under the SIL Open Font License.

Libraries

bank_ui_kit
Bank UI Kit: convenience re-export of core.dart.
core
Core Bank UI Kit library.
credit
Bank UI Kit: Credit sub-library.
investing
Bank UI Kit: Investing sub-library.
saving
Bank UI Kit: Saving sub-library.
social
Bank UI Kit: Social sub-library.