> ## Documentation Index
> Fetch the complete documentation index at: https://docs.whop.com/llms.txt
> Use this file to discover all available pages before exploring further.

# ListElement

> The holdings behind an account's balance. Every currency and token gets its own row, showing its name and its value in dollars, largest first. Rows can report which one the viewer tapped, so you can open your own screen for it.

<Info>**Upcoming.** These docs cover unreleased development, ahead of any published release. Use the channel picker at the top of the sidebar for the docs of a published release.</Info>

*In development, not yet part of a stable release.*

<Tabs>
  <Tab title="Web">
    Belongs to the [`Balances`](/elements/upcoming/wallet/balances) sub-controller in the [`Wallet`](/elements/upcoming/wallet/overview) group. Render `<ListElement />` inside `<Balances>` (React), or mint the sub and mount off it (vanilla): `wallet.create('balances', { … }).create('list', { … })`. Consumer props and `on<Event>` callbacks both go in the create options / JSX props.

    ## Preview

    A live, interactive demo of this element with sample data:

    <div data-whop-demo-shell style={{ position: "relative", minHeight: "320px", transition: "min-height 200ms ease" }}>
      <div data-whop-demo-skeleton style={{ position: "absolute", inset: "0", borderRadius: "12px", background: "rgba(140, 140, 140, 0.12)", pointerEvents: "none", transition: "opacity 200ms ease" }} />

      <div data-whop-demo-native="element:balances/list" data-whop-elements-version="" style={{ position: "relative" }} />
    </div>

    ## Usage

    <div data-whop-usage="wallet/balances-list">
      <CodeGroup>
        ```tsx React theme={null}
        import { WhopElements, Wallet, Balances, ListElement } from "@whop/elements-react";
        import { loadWhop } from "@whop/elements";

        function Example() {
          return (
            <WhopElements elements={loadWhop()}>
              <Wallet /* options */>
                <Balances>
                  <ListElement onBalanceSelected={(payload) => console.log("balanceSelected", payload)} onAccountSelected={(payload) => console.log("accountSelected", payload)} />
                </Balances>
              </Wallet>
            </WhopElements>
          );
        }
        ```

        ```html Vanilla theme={null}
        <script src="https://js.whop.cloud/elements/amber/elements.js" data-whop-elements></script>
        <script type="module">
          const wallet = window.WhopElements().wallet.create({ /* options */ });
          const balances = wallet.create('balances', { /* options */ });
          balances.create('list', {
            onBalanceSelected: (payload) => console.log("balanceSelected", payload),
            onAccountSelected: (payload) => console.log("accountSelected", payload)
          }).mount('#wallet-balances-list');
        </script>
        ```
      </CodeGroup>
    </div>

    ## Props

    <ResponseField name="accessToken" type="string">
      A scoped token for the read. An account needs `company:balance:read`; a user's holdings or owned-account list needs `user:balance:read`. Mint it on your server with `POST /v1/access_tokens`. Without it the read uses the viewer's own session, which only works same-origin.
    </ResponseField>

    <ResponseField name="includeOwnedAccounts" type="boolean">
      For a user's `user_…` account, list their personal balance followed by every owned account the backend returns instead of listing the holdings inside their personal account. Ignored for an account. Defaults to `false`.
    </ResponseField>

    <ResponseField name="showSourceCurrency" type="boolean">
      Show each row in the currency it is held in (€4.20, 0.00000009 cbBTC) and put the dollar value underneath. Off by default, so every row is in dollars. Defaults to `false`.
    </ResponseField>

    <ResponseField name="showUsdEquivalent" type="boolean">
      Keep the dollar value under a holding shown in its own currency. Only applies when `showSourceCurrency` is on. Defaults to `true`.
    </ResponseField>

    <ResponseField name="showPersonalAccount" type="boolean">
      Keep the personal row when `includeOwnedAccounts` is on. Turn it off if your app has no personal account to open. Defaults to `true`.
    </ResponseField>

    ## Events

    Pass a callback in the create options (or React prop) to receive these.

    ### `onBalanceSelected`

    A holding row was clicked, with `includeOwnedAccounts` off. `key` is `usd` for the combined dollar row, otherwise the holding symbol (`cbBTC`, `EUR`), and `kind` tells you which of the three it is so you can route without classifying symbols yourself. The element never navigates.

    **Signature:** `((payload: { key: string; kind: "usd" | "cash" | "asset"; }) => void)`

    ### `onAccountSelected`

    An account row was clicked, with `includeOwnedAccounts` on. `accountId` is the personal `user_…` tag or an owned `biz_…` tag, and `kind` lets you route without inspecting it. The element never navigates.

    **Signature:** `((payload: { accountId: string; kind: "personal" | "business"; }) => void)`

    ### `onLoaderStart`

    Fired the moment the element's own loading skeleton has painted inside its frame. This is the earliest point a consumer-managed loading state can hand off without ever exposing a blank. Always precedes `onReady`; most consumers only need `onReady`.

    **Signature:** `(() => void)`

    ### `onReady`

    Fired once the element has booted and painted its first complete frame.

    **Signature:** `(() => void)`

    ### `onError`

    Fired when the element fails to load or crashes; the element shows its own error fallback. `message` is human-readable; framework refusals also carry `code` (e.g. `HOST_SOURCE_FAILED`, with `sourceKey` naming the failed hostState key) so hosts can switch on codes, never message text.

    **Signature:** `((e: { message: string; code?: string | undefined; sourceKey?: string | undefined; }) => void)`

    ## Methods

    Call these on the element handle, which is the return of `create` (vanilla) or the component `ref` (React).

    ### `mount`

    Place the element on the page: appends its container to `target` (a CSS selector or an element) and starts loading. Nothing renders until this is called. React consumers never call it; the component mounts itself.

    **Signature:** `(target: string | HTMLElement) => void`

    ### `destroy`

    Remove the element from the page and release its frame and subscriptions. Safe to call more than once. React consumers never call it; unmounting the component does it.

    **Signature:** `() => void`

    ### `update`

    Change this element's consumer props after mount, and it re-renders with the merged props. React consumers never call it; updating the JSX props does the same.

    **Signature:** `(options: Partial<ListElementProps>) => void`

    ## Styling

    Each part below is a stable class name, safe to depend on. Restyle a part by mapping its class to a **style declaration object** under `appearance.classes` (properties camelCase or kebab-case, values as strings with units, the same shape as React's `style` prop). The element renders in its own frame, so page stylesheets can't reach it: these declarations are sanitized against a safe-property allowlist and injected inside the frame for you.

    | Class                   | Targets                                             |
    | ----------------------- | --------------------------------------------------- |
    | `.whop-BalanceRow`      | One balance row — its icon, name, value and chevron |
    | `.whop-BalancesSurface` | The balances list — one row per holding or account  |

    ```ts theme={null}
    const wallet = whop.wallet.create({
      appearance: {
        classes: {
          'whop-BalanceRow': { borderRadius: '8px', fontWeight: '600' },
          'whop-BalancesSurface': { borderRadius: '8px', fontWeight: '600' }
        }
      }
    });

    // restyle live at any point, the same shape through update()
    wallet.update({
      appearance: { classes: { 'whop-BalanceRow': { fontWeight: '700' } } }
    });
    ```

    In React, pass the same object as the `appearance` prop on `<Wallet>`; `appearance` also applies globally at `WhopElements({ appearance })`.
  </Tab>

  <Tab title="Swift">
    <div style={{ display: "flex", gap: "2.5rem", alignItems: "flex-start", flexWrap: "wrap" }}>
      <div style={{ flex: "1 1 24rem", minWidth: 0 }}>
        `ListElement` shows what an account holds: every currency and token on its own row, valued in dollars, largest first. It loads its own data, so the only thing you have to pass in is the account id. Pass a closure as well and the rows become tappable. The root is a `VStack`, so it sizes to its content and fills the width you give it.

        ### Usage

        ```swift theme={null}
        import SwiftUI
        import WhopElements

        // WhopSDK.configure(tokenProvider:) runs once at app launch. See Getting started.
        struct WalletScreen: View {
            var body: some View {
                ListElement(
                    accountId: "biz_xxxx"
                ) { balance in
                    print(balance.symbol)
                }
            }
        }
        ```

        ### Parameters

        <ResponseField name="accountId" type="String" required>
          The account whose money the view reads, given as a company's `biz_…` tag. A `user_…` tag reads the viewer's own balance and needs viewer authentication (`WhopSDK.configureWithOAuth`), not an account token.
        </ResponseField>

        <ResponseField name="onBalanceSelected" type="((WalletBalance) -> Void)?">
          Called with the row the viewer tapped. Omit it and the rows render without chevrons, and tapping does nothing.
        </ResponseField>

        ### `WalletBalance`

        What a selection hands back:

        * `id: String`: stable per row
        * `symbol: String`: `USD`, `BTC`, …
        * `displayName: String`: the name shown on the row
        * `amountUsd: Decimal`: the row's value in dollars
        * `isCrypto: Bool`: a crypto holding rather than fiat

        ### States

        Shows two placeholder rows while the balances load. An account id that can't be resolved shows `Couldn't load this account.` If the balance read itself fails, the list renders empty rather than showing an error.

        ### Good to know

        * It doesn't scroll on its own, so put it in a `ScrollView` when it shares a screen with other content.
        * Pairs with [`BalanceElement`](/elements/upcoming/wallet/balances-balance#swift), which shows the same account's total and how it changed.

        <Note>
          Authentication is set once for every element, not per element, so `WhopSDK.configure(tokenProvider:)` at app launch is enough. A view mounted before it lands renders a spinner and picks the token up when it arrives. See [Getting started](/elements/upcoming/getting-started) for the token provider. Theme with the `.whopTheme(_:)` modifier.
        </Note>
      </div>

      <div style={{ flex: "0 1 22rem", width: "22rem", maxWidth: "100%" }}>
        <div style={{ position: "sticky", top: "5rem" }}>
          <iframe src="https://app.revyl.ai/embed/f128a268-f5e0-47c1-8919-86e4f04d6876?accentColor=%23111" title="ListElement running on an iPhone simulator" loading="lazy" className="whop-ios-simulator" style={{ width: "100%", aspectRatio: "390 / 800", border: 0, display: "block", borderRadius: "1.25rem" }} allow="fullscreen; clipboard-read; clipboard-write" />
        </div>
      </div>
    </div>
  </Tab>
</Tabs>
