BESBanking Experience System
Docs Components Journey Showcase
Draft — not yet human-verified. Every gate passing here is automated. No screen-reader, Arabic native-speaker or usability testing has been carried out yet, and all Arabic UI copy is machine-drafted. What has and hasn't been verified
Core components

11 — Core Components: Containers & Surfaces

Banking Experience System (BES) · Core Components · v2.0.0-draft

Live example

Card container
One concept per card. Dense surfaces prefer flat sections with dividers.
Code
<div class="demo-row" style="align-items:flex-start">
  <div class="bes-card" style="max-width:300px">
    <div style="font-weight:600;margin-bottom:4px">Card container</div>
    <div style="font-size:13.5px;color:var(--bes-text-secondary)">One concept per card. Dense surfaces prefer flat sections with dividers.</div>
  </div>
  <button class="bes-btn bes-btn--secondary" data-bes-open="doc-modal">Open confirm dialog</button>
</div>
<div class="bes-scrim" id="doc-modal" role="dialog" aria-modal="true" aria-labelledby="doc-m-t">
  <div class="bes-modal">
    <h3 id="doc-m-t">Remove beneficiary Rajesh Kumar?</h3>
    <p>You'll need to add them again to send money — and new payees may have a 24-hour holding period.</p>
    <div class="actions">
      <button class="bes-btn bes-btn--secondary" data-bes-close="doc-modal">Keep beneficiary</button>
      <button class="bes-btn bes-btn--destructive-solid" data-bes-close="doc-modal">Remove beneficiary</button>
    </div>
  </div>
</div>

Components: Card · List & List Item · Table · Accordion · Modal Dialog · Drawer · Bottom Sheet · Popover · Tooltip · Divider.


Card

Anatomy: container (surface.primary, elevation.1, radius.md) · optional header (title + action) · body · optional footer.

Variants: static (grouping) · interactive (whole card tappable — one action only; internal buttons preclude whole-card tap) · summary (dashboard modules).

States: default · hover (interactive only) · focus · pressed · loading (skeleton body) · error (inline retry) · empty.

Usage: cards group one concept. Anti-decoration rule: no card-inside-card beyond two levels; if everything is a card, nothing is — dense data surfaces (tables, corporate) prefer flat sections with dividers.

Financial: money summary cards state their freshness when not real-time ("As of 14:32"); a card containing a balance respects the masked-balance setting.

A11y: interactive card is a single named control ("Current account, AED 25,000.00 available, view details"); internal structure headed properly.

RTL: header action at inline-end; content mirrors via logical properties.


List & List Item

Anatomy (item): leading slot (icon/avatar/logo) · primary text · secondary text · trailing slot (amount/chevron/status/control) · optional third line (metadata).

Variants: navigation item · selection item (radio/checkbox embedded) · display item · transaction item (specialized, doc 15).

States: default · hover · focus · pressed · selected · disabled · swipe-actions (mobile: max 2 per side, destructive requires confirm — swipe never completes a destructive act alone).

Usage: height per density (64/56/44); dividers border.default inset from leading slot; grouped lists with sticky section headers (dates in transaction lists).

A11y: whole row is the target for navigation items; embedded controls get discrete focus stops; three-line max for readability.

RTL: leading/trailing swap visually; amounts in trailing slot remain LTR runs, end-aligned.


Table

Anatomy: caption/title · column headers (sortable: label + direction arrow) · rows · numeric columns end-aligned tnum · optional row selection checkboxes · sticky header · footer (totals) · toolbar (search, filters, density toggle, export).

Variants: simple · data table (sort/filter/select/bulk) · comparison table (products; first column sticky).

States: default · loading (skeleton rows preserving column widths) · empty (with cause + action) · error (retry) · row hover/selected · sorted column · filtered (active-filter chips above, clearable).

Usage: desktop/SME/corporate density workhorse. On mobile, tables transform — defined per table: transaction tables become Lists; comparison tables become swipeable cards; approval tables become stacked cards with inline actions. A horizontally scrolling raw table on mobile is a last resort and must keep the identifying column sticky.

Financial: amount columns end-aligned with sign and color rules (doc 07); totals row uses type.amount.md; bulk selection surfaces a summary bar ("12 payments selected — total AED 84,300.00") before bulk actions; sort default is newest-first for time data.

A11y: real table semantics (th/scope); sort state announced; row actions reachable by keyboard; selection count live-announced.

RTL: column order mirrors; numeric columns stay end-aligned (visual left in Arabic); sort arrows unmirrored (vertical semantics).


Accordion

Anatomy: header (label + optional metadata + chevron) · panel.

Usage: progressive disclosure of secondary detail (fee breakdowns, FAQ, transaction metadata). Disclosure rule: anything the user must see to decide (total fees, key risks) is outside accordions on review screens — accordions elaborate, they never hide obligations.

States: collapsed · expanded · focus · disabled.

A11y: button header with expanded state; panel labeled by header; multiple-open allowed (no auto-collapse on data surfaces).

RTL: chevron mirrors (points inline-start when open per convention chosen: chevron-down rotates — unmirrored vertical rotation, documented).


Modal Dialog

Anatomy: scrim · surface (elevation.3) · title · body · action row (primary at inline-end, cancel at inline-start) · close (only when closing is safe).

Variants: confirmation (decision) · alert (acknowledge) · task (short embedded form) — anything longer is a screen, not a modal.

States: open · closing-guard (unsaved input → confirm discard).

Usage: modals interrupt; reserve for decisions that must block ("Remove beneficiary Rajesh Kumar? You'll need to add them again to send money."). Money-moving confirmation happens on screens, not modals — a modal confirm for AED 250,000 is too light. Destructive confirms name the object and consequence; buttons echo outcomes ("Remove beneficiary" / "Keep beneficiary").

A11y: focus trapped, initial focus on the least-destructive action, Esc closes (unless closing-guard), focus returns to trigger; title is the accessible name.

RTL: action order mirrors with logical placement; close at inline-end.


Drawer (desktop side panel)

Anatomy: surface sliding from inline-end · header (title + close) · body · optional footer actions.

Usage: contextual detail beside data (transaction detail next to the table, approval detail in corporate queues) — preserves list context. Width 400–560px; push or overlay per surface density.

States: open · closed · stacked (max 2; breadcrumb within).

A11y: focus management as dialog when overlay, as region when push; close returns focus to the row.

RTL: slides from inline-end (visual left in Arabic).


Bottom Sheet (mobile)

Anatomy: grabber · title · content · detents (medium/full) · scrim.

Usage: contextual actions, pickers, short confirmations, in-context explanations ("Why this fee?"). Full flows use screens. Critical warnings (fraud) never use sheets (dismissable-by-swipe is too weak).

States: medium · full · dragging · closing-guard for inputs.

A11y: dialog semantics; swipe-to-close paired with a visible close button; grabber not the only affordance.


Popover

Anatomy: anchored surface (elevation.2) with arrow · content (rich: text, links, small forms) · close on outside-tap/Esc.

Usage: desktop contextual detail (rate breakdown hover-to-detail, calendar legends). On touch, popovers become bottom sheets automatically.

A11y: triggered by click/Enter (never hover-only for content that matters); focusable content reachable.

RTL: anchors and arrows flip logically.


Tooltip

Anatomy: short text label on hover/focus.

Usage: names icon-only controls; ≤ 8 words; never contains information unavailable elsewhere; never on mobile as the sole explanation (use help text or an info popover→sheet).

A11y: appears on focus as well as hover; not the accessible-name mechanism itself (that's aria-label) but supplementary.


Divider

border.default, 1px; section dividers full-bleed, item dividers inset from leading content; vertical dividers only in toolbars/dense headers. Semantic (hr) only when it separates true sections for assistive tech; otherwise decorative and hidden.


All components in this family — live

Every component from this specification, rendered by the coded library. Expand "Code" to copy the markup.

List & data table

PayeeAmount (AED)Status
Gulf Star Trading LLC250,000.00Awaiting approval
DEWA843.50Completed
Etisalat399.00Completed
Code
<div class="demo-stack">
  <div class="bes-list" style="max-width:460px">
    <button class="bes-item" type="button">
      <span class="main"><span class="t">Statements</span><br><span class="s">Monthly PDF and CSV</span></span>
      <span class="trail" style="color:var(--bes-text-disabled)">›</span>
    </button>
    <button class="bes-item" type="button">
      <span class="main"><span class="t">Limits</span><br><span class="s">Daily transfer AED 50,000</span></span>
      <span class="trail" style="color:var(--bes-text-disabled)">›</span>
    </button>
  </div>
  <div class="bes-table-wrap">
    <table class="bes-table" data-bes-sortable>
      <thead><tr><th data-sort="text">Payee</th><th class="num" data-sort="num">Amount (AED)</th><th>Status</th></tr></thead>
      <tbody>
        <tr><td>Gulf Star Trading LLC</td><td class="num">250,000.00</td><td><span class="bes-badge bes-badge--warning">Awaiting approval</span></td></tr>
        <tr><td>DEWA</td><td class="num">843.50</td><td><span class="bes-badge bes-badge--success">Completed</span></td></tr>
        <tr><td>Etisalat</td><td class="num">399.00</td><td><span class="bes-badge bes-badge--success">Completed</span></td></tr>
      </tbody>
    </table>
  </div>
</div>

Accordion — elaborates, never hides obligations

Why this fee?
The transfer fee covers processing through the international payment network. Full schedule of charges (PDF).
When does the money arrive?
Transfers to India usually arrive within 1 hour. Same-day cut-off is 22:00 UAE time.
Code
<div class="bes-accordion" style="max-width:460px">
  <details><summary>Why this fee?</summary><div class="body">The transfer fee covers processing through the international payment network. Full <a href="#">schedule of charges (PDF)</a>.</div></details>
  <details><summary>When does the money arrive?</summary><div class="body">Transfers to India usually arrive within 1 hour. Same-day cut-off is 22:00 UAE time.</div></details>
</div>

Drawer

Code
<button class="bes-btn bes-btn--secondary" data-bes-drawer-open="dc-drawer">Open transaction drawer</button>
<div class="bes-drawer-scrim" id="dc-drawer-scrim"></div>
<aside class="bes-drawer" id="dc-drawer" role="dialog" aria-labelledby="dc-dr-t">
  <div class="head"><h3 id="dc-dr-t">Carrefour · <bdi class="bes-amount">−AED 89.50</bdi></h3>
  <button class="bes-iconbtn" data-bes-drawer-close="dc-drawer" aria-label="Close">✕</button></div>
  <div class="body">
    <div class="bes-rows">
      <div class="bes-row"><span class="k">Status</span><span class="v"><span class="bes-badge bes-badge--success">Completed</span></span></div>
      <div class="bes-row"><span class="k">Card</span><span class="v"><bdi class="bes-amount">••8834</bdi> · Contactless</span></div>
      <div class="bes-row"><span class="k">Reference</span><span class="v"><bdi class="bes-amount">TXN-88213-AE</bdi></span></div>
    </div>
  </div>
</aside>

Tooltip & popover

Copy IBAN Hover or focus the button — tooltips name icon-only controls, never carry unique information.
Code
<div class="demo-row">
  <span class="bes-pop">
    <button class="bes-iconbtn bes-iconbtn--bordered" aria-label="Copy IBAN">
      <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 class="tip" role="tooltip">Copy IBAN</span>
  </span>
  <span style="font-size:13px;color:var(--bes-text-secondary)">Hover or focus the button — tooltips name icon-only controls, never carry unique information.</span>
</div>