Commerce & auth
Wallet Balance
Interactive payment cards tucked into a leather pouch with eye-toggle balance obscuring
detent-wallet-balance
Port status
- Catalog status
- implemented
- Origin
- upstream
- Phase
- 3
- Wave
- phase-3-data
- Group
- Commerce & auth
6.5 KB gzip for the class module
Variants
Sample data; nothing is fetched or sent. Press the eye to mask every balance: the amounts are replaced by
******, so the real values are not in the DOM while hidden, and a polite live region announces
Total balance … or Balances hidden. This pouch is filled through the property-only
accounts array in euros. Every toggle emits one composed detent-visible-change with
{ visible }; the demo only logs it.
Recorded states
pressedrecorded state; no setterreduced motionrecorded state; no setter
Usage
Import
import '/components/wallet-balance/define.js';
// or register it yourself
import { DetentWalletBalance } from '/components/wallet-balance/wallet-balance.js';
Attributes
currencydefault-visiblelocaletotal-labelvisible
Properties
accountsonVisibleChange
Slots
No slots are recorded for this component.
Events
detent-visible-change— {}
Example
Runnable example: site/examples/wallet-balance.ts. The snippet below is generated from the catalogued attributes.
<detent-wallet-balance
currency="USD"
default-visible
locale="en-US"
total-label="Total Balance"
visible
></detent-wallet-balance>
Property-only values
const element = document.querySelector('detent-wallet-balance');
if (element !== null) {
// accounts: WalletAccount[]
element.accounts = [];
// onVisibleChange: (visible: boolean) => void
element.onVisibleChange = () => {};
}
Source
The pinned upstream source for this row:
src/components/ui/WalletBalance.tsxsha256 f5b368575784…
Native files
The native module and its artifacts:
src/components/wallet-balance/wallet-balance.tssrc/components/wallet-balance/styles.csssrc/components/wallet-balance/define.tsdocs/components/wallet-balance.mdsite/examples/wallet-balance.tstests/browser/wallet-balance.spec.tsevidence/components/wallet-balance.md
API
Boolean attributes follow HTML presence semantics: present means true, absent means false, and disabled="false" still means disabled.
Attributes
| Attribute | Property | Type | Default | Notes |
|---|---|---|---|---|
currency | currency | string | 'USD' | Kebab-case attribute; camelCase property. |
default-visible | defaultVisible | boolean | true | Presence semantics: present means true, absent means false. |
locale | locale | string | 'en-US' | Kebab-case attribute; camelCase property. |
total-label | totalLabel | string | 'Total Balance' | Kebab-case attribute; camelCase property. |
visible | visible | boolean | undefined | Presence semantics: present means true, absent means false. |
Properties
| Property | Type | Default | Notes |
|---|---|---|---|
accounts | WalletAccount[] | DEFAULT_ACCOUNTS | Property-only: assign from script; not accepted as an attribute. |
onVisibleChange | (visible: boolean) => void | undefined | Property-only: assign from script; not accepted as an attribute. |
Events
| Event | Upstream prop | Payload type | Notes |
|---|---|---|---|
detent-visible-change | onVisibleChange | (visible: boolean) => void | Composed, bubbles; fires only for a user action. |
Slots
No slots are recorded for this component.
CSS customisation
- `className` prop is replaced by documented CSS parts/custom properties; no Tailwind in consumers.
- React callback props become typed composed CustomEvents; programmatic state assignment emits none.
- Framer Motion springs/AnimatePresence ported to CSS transitions, WAAPI or the shared rAF spring helper.
- className is replaced by documented CSS parts and custom properties.
- WalletAccount.logo is a string; the upstream brand marks are typographic stand-ins.
- background and amountColor are validated with CSS.supports(color, ...) and ignored when invalid.
- Default amountColors are darkened (#3a2f66 / #2a4f1b / #4a4a4a) so each reaches 4.5:1 on its default brand surface.
- mask/maskClassName/show/value/open are internal EyeIcon/Swap params, not host API: observedAttributes is exactly visible, default-visible, currency, locale and total-label.
- The mask replaces one text node where upstream crossfaded two AnimatePresence children; that is what makes the no-amount-in-the-DOM-while-hidden guarantee provable.
- Framer springs become a cubic-bezier(0.34,1.3,0.64,1) transform transition with the upstream 0.03 s stagger (PC-10.4 substitution; the motion gate stays open).
- The totals block sits 9px lower than upstream so its opaque pouch-coloured paint, which makes the contrast measurable, clears the dashed stitch.
What it does
Three brand cards tucked into a leather pouch, an eye toggle that obscures or reveals every balance with a blur crossfade, staggered fan/tuck transitions and a polite live region.
Upstream behaviour
- Interactive eye-toggle button to reveal or mask balances with blur-crossfade and popLayout transitions
- Staggered spring animations for fanning out and tucking cards into the pouch
- Responsive stage scaling with ResizeObserver for crisp rendering on any viewport width
- Customizable accounts array with brand marks, individual balances, and background themes
- Full accessibility support with aria-pressed, live screen reader announcements, and prefers-reduced-motion
Differences from upstream
- `className` prop is replaced by documented CSS parts/custom properties; no Tailwind in consumers.
- React callback props become typed composed CustomEvents; programmatic state assignment emits none.
- Framer Motion springs/AnimatePresence ported to CSS transitions, WAAPI or the shared rAF spring helper.
- className is replaced by documented CSS parts and custom properties.
- WalletAccount.logo is a string; the upstream brand marks are typographic stand-ins.
- background and amountColor are validated with CSS.supports(color, ...) and ignored when invalid.
- Default amountColors are darkened (#3a2f66 / #2a4f1b / #4a4a4a) so each reaches 4.5:1 on its default brand surface.
- mask/maskClassName/show/value/open are internal EyeIcon/Swap params, not host API: observedAttributes is exactly visible, default-visible, currency, locale and total-label.
- The mask replaces one text node where upstream crossfaded two AnimatePresence children; that is what makes the no-amount-in-the-DOM-while-hidden guarantee provable.
- Framer springs become a cubic-bezier(0.34,1.3,0.64,1) transform transition with the upstream 0.03 s stagger (PC-10.4 substitution; the motion gate stays open).
- The totals block sits 9px lower than upstream so its opaque pouch-coloured paint, which makes the contrast measurable, clears the dashed stitch.