10 — Core Components: Navigation
Banking Experience System (BES) · Core Components · v2.0.0-draft
Live example
Code
<div class="demo-stack" style="max-width:560px">
<div>
<div class="bes-tabs" role="tablist" aria-label="Account sections">
<button class="bes-tab" role="tab" aria-selected="true" aria-controls="dp-1" id="dt-1">Transactions</button>
<button class="bes-tab" role="tab" aria-selected="false" aria-controls="dp-2" id="dt-2" tabindex="-1">Details</button>
<button class="bes-tab" role="tab" aria-selected="false" aria-controls="dp-3" id="dt-3" tabindex="-1">Statements</button>
</div>
<div id="dp-1" role="tabpanel" aria-labelledby="dt-1" style="padding:12px 2px;font-size:14px;color:var(--bes-text-secondary)">214 transactions this quarter.</div>
<div id="dp-2" role="tabpanel" aria-labelledby="dt-2" hidden style="padding:12px 2px;font-size:14px;color:var(--bes-text-secondary)">IBAN, SWIFT and account facts.</div>
<div id="dp-3" role="tabpanel" aria-labelledby="dt-3" hidden style="padding:12px 2px;font-size:14px;color:var(--bes-text-secondary)">Monthly statements, PDF and CSV.</div>
</div>
<div class="bes-stepper" aria-label="Progress: step 2 of 4">
<span class="bes-step bes-step--done"><span class="n">✓</span> Amount</span>
<span class="bes-step-bar"></span>
<span class="bes-step bes-step--current"><span class="n">2</span> Recipient</span>
<span class="bes-step-bar"></span>
<span class="bes-step"><span class="n">3</span> Review</span>
<span class="bes-step-bar"></span>
<span class="bes-step"><span class="n">4</span> Done</span>
</div>
</div>Components: App Bar (top) · Bottom Navigation · Side Navigation · Tabs · Segmented Control · Breadcrumb · Pagination · Stepper (Progress) · Language Switcher · Session Bar.
App Bar (Top)
Anatomy: back/close at inline-start · title (screen question, e.g. "Send money") · contextual actions at inline-end (≤2 + overflow) · optional subtitle (account context: "From Current account ••4521").
States: default · scrolled (elevation on) · contextual (in-flow variant locks navigation to Back/Cancel only).
Usage: in money flows the bar shows step context ("Send money · Step 2 of 4") and Cancel behavior is explicit — cancelling a DRAFT asks nothing; cancelling past AUTHENTICATION confirms ("Your transfer hasn't been sent. Leave anyway?").
A11y: title is the page heading (h1); back has accessible name naming the destination ("Back to Payees").
RTL: back chevron mirrors and sits at inline-start (visual right in Arabic); title alignment start.
Bottom Navigation (mobile)
Anatomy: 4–5 destinations: icon + label (labels always visible — icon-only bottom nav is banned) · badge slot (approvals count, unread).
Default retail set: Home · Payments · Cards · Hub (Products/More) · Profile. SME set: Home · Payments · Approvals · Accounts · More.
States: active (filled icon + action.primary tint) · inactive · badge (numeric ≤99, then "99+").
Usage: persistent across top-level destinations; hidden inside money flows (flows are modal journeys with the App Bar contract).
A11y: tab-bar semantics; active announced; badges included in name ("Approvals, 3 pending").
RTL: order mirrors (first destination at visual right).
Side Navigation (desktop / SME / corporate)
Anatomy: product switcher region · sections with headers · items (icon + label + badge) · collapse toggle · footer (settings, language, session).
States: expanded · collapsed (icons + tooltips) · item active/hover/focus · section collapsed.
Financial: corporate surfaces pin Approvals with live count; entity/company switcher at top for multi-entity users, with the active entity always visible ("Al Noor Trading LLC — AED accounts").
A11y: landmark nav with label; collapse state persists; keyboard operable throughout.
RTL: docks at inline-start (visual right in Arabic); collapse chevrons mirror.
Tabs
Anatomy: tab list · tabs (label + optional count) · active indicator · panels.
States: active · inactive · hover · focus · disabled (avoid; explain emptiness inside the panel instead).
Usage: peer views of one object (Account: Transactions / Details / Statements). Never for sequential steps (that's Stepper) and never nested two-deep.
Financial: counts on tabs reflect filtered results ("Pending (3)"); tab state preserved on back-navigation.
A11y: tablist pattern, arrow-key navigation, panel labeled by tab.
RTL: order and active-indicator animation mirror; horizontal scroll (if overflowing) starts from inline-start.
Segmented Control
Anatomy: 2–4 segments, equal width, single selection.
Usage: view toggles within one dataset (AED / USD display; List / Chart; Monthly / Yearly). Not for navigation, not for actions.
States: selected · unselected · focus · disabled.
A11y/RTL: radiogroup semantics; order mirrors; selection thumb animation mirrors.
Breadcrumb (desktop, deep hierarchies)
Anatomy: links + separator chevron · current page (non-link).
Usage: SME/corporate/back-office depth ("Payments › Bulk payments › July payroll › Payment 41 of 60"). Consumer mobile never shows breadcrumbs.
A11y: nav landmark "Breadcrumb"; current page marked.
RTL: chevrons mirror; order mirrors.
Pagination
Anatomy: prev/next · page numbers or range readout ("41–60 of 214") · optional page-size select.
Usage: desktop tables. Mobile lists use progressive loading with an explicit "Load more" (auto-infinite scroll is banned on transaction lists — it breaks "find the receipt from March" tasks and footer reachability).
Financial: table pagination preserves filters/sort in URL/state; exports respect the filtered set, stated ("Export 214 filtered transactions").
A11y: current page announced; range readout is live text.
RTL: prev/next mirror.
Stepper (Progress)
Anatomy: steps (number/check + label) · connectors · current highlight; horizontal (≤4 visible steps) or compact "Step 2 of 4" text form (mobile default).
States per step: complete (check) · current · upcoming · blocked (with reason) · error (needs revisit).
Usage: every multi-step financial journey ≥3 steps shows position; steps are nouns ("Amount", "Review") not verbs; completed steps are tappable to revisit before AUTHENTICATION, locked after.
A11y: list semantics with state per step ("Step 2 of 4, Amount, current step").
RTL: flows inline — visual right-to-left in Arabic; connector/animation mirror; checkmarks unmirrored.
Language Switcher
Anatomy: globe icon + current language label ("العربية" shown in Arabic when the UI is English, and "English" in English when the UI is Arabic — each language named in itself, always).
Usage: available pre-login and in Profile; switching swaps language and direction live, preserving screen position and any draft state; never resets a flow.
A11y: announces the switch; lang attributes update so screen readers change voice.
Session Bar (security navigation)
Anatomy: timeout countdown region (appears at T-60s: "You'll be signed out in 0:59 — Stay signed in") · sign-out control · last-login note on Home ("Last sign-in: yesterday 21:14, Dubai").
States: hidden · warning · expired (route to the Session Expired page, doc 25, preserving safe drafts).
A11y: countdown is a polite live region; "Stay signed in" is keyboard-first reachable; expiry never silently discards a payment draft (restored after re-auth with explicit confirmation).
All components in this family — live
Every component from this specification, rendered by the coded library. Expand "Code" to copy the markup.
Breadcrumb & pagination
Code
<div class="demo-stack">
<nav aria-label="Breadcrumb"><ol class="bes-breadcrumb">
<li><a href="#">Payments</a></li><li><a href="#">Bulk payments</a></li><li><a href="#">July payroll</a></li><li aria-current="page">Payment 41 of 60</li>
</ol></nav>
<div class="bes-pagination">
<button class="bes-btn bes-btn--secondary bes-btn--sm">Previous</button>
<span class="range"><bdi class="bes-amount">41–60</bdi> of <bdi class="bes-amount">214</bdi></span>
<button class="bes-btn bes-btn--secondary bes-btn--sm">Next</button>
</div>
</div>Segmented control
Code
<div class="demo-row">
<div class="bes-seg" role="group" aria-label="View as">
<button aria-pressed="true">List</button><button aria-pressed="false">Chart</button>
</div>
<div class="bes-seg" role="group" aria-label="Currency display">
<button aria-pressed="true">AED</button><button aria-pressed="false">USD</button>
</div>
</div>Bottom navigation (mobile pattern)
Labels always visible; badges included in the accessible name; order mirrors in RTL.
Code
<div style="max-width:390px;border:1px solid var(--bes-border-default);border-radius:14px;overflow:hidden">
<div style="display:flex;background:var(--bes-surface-primary);border-block-start:1px solid var(--bes-border-default)">
<span style="flex:1;text-align:center;padding:10px 0 12px;color:var(--bes-action-primary);font-size:11px;font-weight:600">●<br>Home</span>
<span style="flex:1;text-align:center;padding:10px 0 12px;color:var(--bes-text-secondary);font-size:11px;font-weight:500">○<br>Payments</span>
<span style="flex:1;text-align:center;padding:10px 0 12px;color:var(--bes-text-secondary);font-size:11px;font-weight:500">○<br>Cards</span>
<span style="flex:1;text-align:center;padding:10px 0 12px;color:var(--bes-text-secondary);font-size:11px;font-weight:500;position:relative">○<br>Approvals<span class="bes-badge bes-badge--error" style="position:absolute;inset-block-start:4px;inset-inline-end:14px;padding:1px 6px;font-size:10px">3</span></span>
<span style="flex:1;text-align:center;padding:10px 0 12px;color:var(--bes-text-secondary);font-size:11px;font-weight:500">○<br>Profile</span>
</div>
</div>
<p style="font-size:13px;color:var(--bes-text-secondary);margin:10px 0 0">Labels always visible; badges included in the accessible name; order mirrors in RTL.</p>Session bar — timeout warning
Appears at T-60s; expiry never silently discards a payment draft — it's restored after re-auth.
Code
<div class="bes-banner" style="border-radius:10px;border:1px solid var(--bes-border-default);justify-content:space-between">
<span>You'll be signed out in <bdi class="bes-amount">0:59</bdi></span>
<button class="bes-btn bes-btn--primary bes-btn--sm">Stay signed in</button>
</div>
<p style="font-size:13px;color:var(--bes-text-secondary);margin:10px 0 0">Appears at T-60s; expiry never silently discards a payment draft — it's restored after re-auth.</p>