Industries · Banking
Banking Transaction Row
Banking Transaction Row is a single financial transaction entry — merchant, date, amount, and status — with a Popover for full transaction detail.
Status (success/warning/error) — drives Badge variant and amount color, no top-level variants of its own
betaReact AvailableFigma UnavailableDocs Partial
- React last updated
- 2026-07-25
- Documentation last updated
- 2026-07-25
- Accessibility target
- WCAG 2.2 AA (target)
- Version
- 0.1.0-beta
Known open questions
- No Figma reference exists for this component or for Industry Systems generally — confirmed absent via full file search on 2026-07-25, not an oversight.
- List Item gained aria-expanded/aria-haspopup/aria-controls passthrough for this component's disclosure trigger — a genuine Layer 2 extension, not a Banking-specific workaround (see components/ui/ListItem.tsx).
- Currency/amount formatting is the consumer's responsibility — amount is a pre-formatted display string, not a number with a built-in formatter, consistent with how Account Card and Balance Summary also take pre-formatted figures.
Recent activity
Click any row to open its detail Popover. Status drives both the Badge variant and the amount's color, using the existing semantic/feedback/success, semantic/feedback/warning, and semantic/action/danger tokens — no new colors.
Everyday Checking •••• 4821
Purpose
Banking Transaction Row is a single transaction entry in a financial activity list — merchant, date, amount, and status, with a Popover for full detail. The first Layer 4 Industry Systems pilot component; React-first, no Figma reference exists yet for Industry Systems.
Anatomy
Composes: List Item (row shell) + Avatar (merchant logo/initials) + Badge (status) + Popover (detail trigger, anchored via PopoverAnchor since List Item does not forward a ref).
Variants and states
success · warning · error
When to use
Listing individual financial transactions (purchases, transfers, deposits) where each row needs its own status and an optional detail view without leaving the list.
When not to use
A generic, non-financial row — use List Item directly. A transaction that doesn't need a status or detail view — a plain List Item composition is simpler.
Accessibility
The whole row is a single native button (List Item's action mode) with aria-expanded/aria-haspopup="dialog"/aria-controls reflecting the anchored Popover's open state — added to List Item itself for this, not layered on top of it.
Keyboard behavior
The row is a single native button (List Item's action mode) — Enter/Space toggles the anchored Popover open/closed, matching native button semantics. No composite keyboard model beyond that.
Common mistakes
Wrapping List Item in PopoverTrigger instead of PopoverAnchor — List Item doesn't forward a ref, so PopoverTrigger's clone-based ref assignment silently fails to attach to a real DOM node. Inventing new status colors instead of reusing the existing semantic/feedback/success, semantic/feedback/warning, and semantic/action/danger tokens Alert already establishes for exactly this purpose.
Properties
merchant, merchantLogoSrc?, merchantInitials?, date, amount, status (success/warning/error), statusLabel, detail (ReactNode, typically BankingTransactionDetailRow items).
Why Popover instead of Drawer for the detail view?
Popover's own documented purpose ("non-modal floating panel for supplementary or lightly interactive content anchored to a trigger") precisely matches viewing a handful of read-only detail fields for one row without leaving the transaction list. Drawer's placement is currently left-edge-only, an unconventional position for a per-row detail panel, and Drawer's own description ("supplementary settings, filters, or secondary forms") targets a heavier, more form-like use case than this.
Why PopoverAnchor instead of PopoverTrigger?
PopoverTrigger clones its child and injects a ref for position tracking — List Item does not forward a ref to its underlying interactive element, so that ref would silently fail to attach. PopoverAnchor wrapping a plain div is the same pattern Combobox already uses for its own non-button trigger (its text input).
Tokens used
semantic/feedback/successsemantic/feedback/warningsemantic/action/dangersemantic/text/primarysemantic/text/secondary
Component API
| Prop | Type | Default | Description |
|---|---|---|---|
| merchant | string | — | Merchant or counterparty name — also the row's title and the Avatar's accessible label. |
| merchantLogoSrc | string | — | Optional merchant logo image URL. |
| merchantInitials | string | — | Fallback initials shown when merchantLogoSrc is absent or fails to load. |
| date | string | — | Display date/time string — formatting is the consumer's responsibility. |
| amount | string | — | Pre-formatted amount string (e.g. "-$42.50") — currency formatting is the consumer's responsibility. |
| status | "success" | "warning" | "error" | — | Drives Badge variant and amount color via existing semantic status tokens. |
| statusLabel | string | — | Visible status text (e.g. "Completed", "Pending", "Declined"). |
| detail | ReactNode | — | Content shown in the anchored Popover — typically BankingTransactionDetailRow items. |
React example
Copy React example
import {
BankingTransactionRow,
BankingTransactionDetailRow,
} from "@/components/ui/BankingTransactionRow";
export function Example() {
return (
<ul>
<BankingTransactionRow
merchant="Coffee Collective"
merchantInitials="CC"
date="Jan 12"
amount="-$4.75"
status="success"
statusLabel="Completed"
detail={
<>
<BankingTransactionDetailRow label="Category" value="Dining" />
<BankingTransactionDetailRow label="Transaction ID" value="TX-48213" />
</>
}
/>
</ul>
);
}