14 — Financial Components: Accounts Family
Banking Experience System (BES) · Financial Components · v2.0.0-draft
Live example
Code
<div class="bes-card bes-acct" style="max-width:400px">
<div class="row1">
<div>
<div class="name">Current account</div>
<div class="meta"><bdi class="bes-amount">••4521</bdi> · Personal</div>
</div>
<button class="bes-iconbtn" aria-label="Hide balance" data-bes-mask="doc-bal" aria-pressed="false">
<svg width="20" height="20" viewBox="0 0 20 20" fill="none"><path d="M2 10s3-5.5 8-5.5S18 10 18 10s-3 5.5-8 5.5S2 10 2 10z" stroke="currentColor" stroke-width="1.5"/><circle cx="10" cy="10" r="2.4" stroke="currentColor" stroke-width="1.5"/></svg>
</button>
</div>
<bdi class="bes-amount bes-amount--lg" id="doc-bal"><span class="cur">AED</span> 25,000.00</bdi>
<div class="sub">Available · <bdi class="bes-amount">AED 500.00</bdi> reserved</div>
<div class="actions">
<button class="bes-btn bes-btn--primary bes-btn--sm">Send</button>
<button class="bes-btn bes-btn--secondary bes-btn--sm">Details</button>
</div>
</div>Components: Account Card · Account Selector · Balance Display · Balance Set · Account Details · IBAN Display · Account Status · Product Header · Spaces/Goal Card.
Account Card
Purpose: one account at a glance — the dashboard workhorse.
Anatomy: account name (user-renamable: "Rent account") · product type label ("Current account" / "حساب جاري") · masked number (••4521) · available balance (Amount lg, maskable) · optional pending indicator ("AED 500.00 pending") · optional status badge · primary quick actions (≤2: Send, Details).
Variants: full (dashboard) · compact (lists, pickers) · multi-currency (currency tabs or stacked balances per currency) · joint (co-holder indicator) · ✦ Islamic (product label carries structure: "Mudarabah savings"; profit-rate metadata instead of interest).
States: default · loading (skeleton — no zero flash) · stale (timestamp) · masked · restricted (financial.blocked treatment + "Why?" path) · dormant (reactivation path) · closed (read-only history access).
Usage: available balance is the headline number always (doc 07 §3); current balance relegated to Details. One tap → account home. Cards never show promotional content inside the account object.
A11y: single named control: "Current account ending 4521, AED 25,000.00 available"; quick actions as discrete stops.
RTL: name/labels mirror; number and balance LTR runs; actions at inline-end.
Account Selector
Purpose: choose source/destination account in flows.
Anatomy: Select/Combobox specialization — trigger shows selected account (name + ••number + available balance); options show the same triple; groups: "Your accounts / Joint / Business".
States: default · open · insufficient (option visible but flagged: "AED 120.00 available — not enough for this transfer"; selectable only where partial funding is a real flow, otherwise disabled with reason) · single-account (renders as static confirmation line, not a dropdown).
Financial: in transfer flows, selecting a source re-validates amount + limits instantly; balance shown is available; hidden accounts (user preference) still listed under "More accounts".
A11y: option announced with full triple; insufficient state part of the announcement.
Balance Display
Purpose: a single balance figure with its label and freshness.
Anatomy: label ("Available balance") · Amount · freshness/timestamp when not real-time · optional info affordance explaining the balance type.
Rule: never a bare number — the type of balance is always labeled, because "balance" is ambiguous by definition (doc 07 §3).
Balance Set
Purpose: the full picture — available / current / pending / reserved in one structure.
Anatomy: primary row (available, amount.lg) · secondary rows (current, pending in/out, reserved) · "Why is my available balance different?" explainer link when current ≠ available · holds drill-down (list of reservations with merchant, amount, release date).
Example:
Available balance AED 23,750.00
Current balance AED 25,000.00
Pending out −AED 750.00 (2 transactions)
Reserved (card holds) −AED 500.00 → View holds
A11y: rendered as a definition list; explainer reachable by keyboard.
Account Details
Purpose: the reference sheet — everything needed to receive money or verify the account.
Anatomy: rows for: holder name (legal, as registered) · IBAN Display · account number · branch/bank identifiers (SWIFT/BIC) · currency · product name & terms link · opened date. Each row: label + value + copy button. "Share details" action exports a clean payload (text/PDF) excluding anything not needed for receiving money.
States: default · restricted-view (joint/delegated users see per-permission subsets).
Security: details screens require an authenticated session but not step-up; screenshots allowed (users legitimately share IBANs) — but the share action is the promoted path.
IBAN Display
Purpose: render the 23-character UAE IBAN (and foreign IBANs) reliably.
Anatomy: grouped display AE07 0331 2345 6789 0123 456 · copy button (copies unspaced canonical form; toast confirms "IBAN copied") · always dir="ltr" in an isolated run.
States: default · verifying (payee-side lookups) · invalid (entry-side pairing with the IBAN input, doc 09).
A11y: announced in groups of four, not as one 23-character blur; copy announces success.
Account Status
Purpose: account-level states surfaced honestly.
Vocabulary: active · restricted (with reason class: verification-needed / compliance-hold — tipping-off-safe copy) · dormant (with reactivation steps) · frozen (with support path) · pending-closure · closed.
Anatomy: Status Badge + explanation block + the recovery path (every non-active status names its exit).
Rule: a restricted account's balance remains visible — restriction of action never becomes concealment of the user's own money.
Product Header
Purpose: top-of-screen identity for any financial product page (account, card, loan, deposit).
Anatomy: product name · identifying suffix (••4521) · status badge · headline figure (available balance / outstanding amount / card limit) · tab bar into sections (Transactions / Details / Statements).
RTL: headline figure LTR run; tabs mirror.
Spaces / Goal Card
Purpose: sub-account earmarking (savings goals, VAT set-aside, rent).
Anatomy: goal name + icon/emoji slot · saved amount / target ("AED 6,500 of AED 20,000") · Progress bar · optional auto-rule summary ("Saves AED 500.00 every payday") · quick add/withdraw.
States: on-track · paused · reached (celebration allowed — savings context is the sanctioned celebratory surface, doc 05 §2) · behind (neutral framing: "AED 500 to stay on track" — never shame).
Financial: money in spaces is part of balance.current but excluded from spendable balance.available presentation — the set explains this ("AED 6,500.00 set aside in Spaces").
All components in this family — live
Every component from this specification, rendered by the coded library. Expand "Code" to copy the markup.
Balance set — the full truth
Code
<div class="bes-card" style="max-width:420px">
<div class="bes-rows">
<div class="bes-row"><span class="k" style="color:var(--bes-text-primary);font-weight:600">Available balance</span><span class="v"><bdi class="bes-amount bes-amount--md">AED 23,750.00</bdi></span></div>
<div class="bes-row"><span class="k">Current balance</span><span class="v"><bdi class="bes-amount">AED 25,000.00</bdi></span></div>
<div class="bes-row"><span class="k">Pending out</span><span class="v"><bdi class="bes-amount">−AED 750.00</bdi> <span style="color:var(--bes-text-secondary);font-weight:400">(2)</span></span></div>
<div class="bes-row"><span class="k">Card holds</span><span class="v" style="color:var(--bes-financial-reserved)"><bdi class="bes-amount">−AED 500.00</bdi></span></div>
</div>
<a href="#" style="font-size:13.5px;font-weight:500">Why is my available balance different?</a>
</div>Account selector
Code
<div class="bes-field" style="max-width:380px;margin-bottom:0">
<label class="bes-label" for="da-src">From account</label>
<div class="bes-select"><select id="da-src">
<option>Current account ••4521 — AED 23,750.00 available</option>
<option>Savings ••8102 — AED 46,200.00 available</option>
<option disabled>Joint account ••3377 — AED 120.00 (not enough for this transfer)</option>
</select></div>
<div class="bes-help">Options always show name, masked number and available balance.</div>
</div>IBAN display with copy
Code
<div class="demo-row">
<bdi class="bes-amount" style="font-size:15px;font-weight:600;letter-spacing:.04em">AE07 0331 2345 6789 0123 456</bdi>
<button class="bes-iconbtn" aria-label="Copy IBAN" data-bes-copy="AE070331234567890123456" data-bes-copied="IBAN copied">
<svg width="18" height="18" viewBox="0 0 18 18" fill="none"><rect x="6" y="6" width="9" height="9" rx="1.5" stroke="currentColor" stroke-width="1.5"/><path d="M12 6V4.5A1.5 1.5 0 0 0 10.5 3H4.5A1.5 1.5 0 0 0 3 4.5v6A1.5 1.5 0 0 0 4.5 12H6" stroke="currentColor" stroke-width="1.5"/></svg>
</button>
<span style="font-size:13px;color:var(--bes-text-secondary)">Displays grouped; copies unspaced; always an LTR run — flip a doc-demo direction and it holds.</span>
</div>Spaces / goal card
Code
<div class="bes-card bes-goal" style="max-width:380px">
<div class="head"><span class="name">🏠 Rent — September</span><span class="bes-badge bes-badge--success">On track</span></div>
<div class="bes-progress"><div class="fill" style="inline-size:65%"></div></div>
<div class="figs"><b><bdi class="bes-amount">AED 6,500.00</bdi></b> of <bdi class="bes-amount">AED 10,000.00</bdi> · saves <bdi class="bes-amount">AED 500.00</bdi> every payday</div>
<div class="demo-row" style="margin-top:12px">
<button class="bes-btn bes-btn--secondary bes-btn--sm">Add money</button>
<button class="bes-btn bes-btn--ghost bes-btn--sm">Withdraw</button>
</div>
</div>