TokenBalance
Token balance display with auto-formatting, fiat conversion, and polling. Supports native tokens (ETH, MATIC) and ERC-20 tokens.
Bundle: 4.6 kB JS (gzip) + 2.1 kB CSS (gzip).
Import
import { TokenBalance } from '@txkit/react'Usage
<TokenBalance />Shows the connected wallet's native token balance with USD equivalent.
For ERC-20 tokens, pass the contract address:
<TokenBalance token="0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48" />Props
| Prop | Type | Default |
|---|---|---|
className | string | - |
children | (data: TokenBalanceRenderData) => ReactNode | - |
variant | 'inline' | 'row' | 'inline' |
token | `0x${string}` | - |
name | string | - |
icon | string | - |
address | `0x${string}` | Connected wallet |
chainId | number | Current chain |
fiatCurrency | string | 'USD' |
price | number | - |
refetchInterval | number | pollingInterval from config |
formatOptions | TokenBalanceFormatOptions | See Formatting |
labels | Partial<TokenBalanceLabels> | See Labels |
showFiat | boolean | true |
showIcon | boolean | true |
showSymbol | boolean | true |
onBalanceChange | (balance: bigint, prevBalance: bigint | undefined) => void | - |
onError | (error: Error) => void | - |
-
variant-inlineis the default compact display (icon, balance, symbol on one line).rowswitches to a token-list layout withnameon the first line and balance + fiat on the second - meant for portfolio tables. -
name- Token display name shown only invariant="row"(e.g. "USD Coin"). Thesymbolis auto-resolved from the contract. -
token- ERC-20 contract address. When omitted, shows the native token (ETH, MATIC, etc.). -
icon- Token icon URL. Displayed as a 20px circle before the balance. -
address- Override whose balance to show. Defaults to the connected wallet. -
price- Manual USD price override. Skips the DeFiLlama price fetch. -
children- Render function for full UI control. Receives TokenBalanceRenderData.
States
| State | Shows | Behavior |
|---|---|---|
loading | Skeleton pulse animation | Fetching balance from RPC |
ready | Formatted balance + fiat | Auto-refetches on refetchInterval |
zero | 0 with dimmed style | Balance is exactly 0n - not an error, fiat hidden by default |
error | "Failed to load" text | Calls onError if provided |
The data-state attribute on the root element exposes the current state for custom styling ([data-state="loading"], [data-state="ready"], [data-state="error"]). The data-zero attribute is set on the ready state when balance is zero.
Examples
ERC-20 Token
<TokenBalance token="0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48" />Row Variant (Portfolio Tables)
Switches from inline (icon + balance + symbol on one line) to a stacked layout
suitable for token lists or portfolio rows. The first line shows name, the
second line shows balance + fiat.
<TokenBalance
variant="row"
token="0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"
name="USD Coin"
icon="https://assets.coingecko.com/coins/images/6319/small/usdc.png"
/>For multi-token portfolio displays:
<div role="list">
<TokenBalance variant="row" name="Ether" />
<TokenBalance variant="row" token={USDC} name="USD Coin" />
<TokenBalance variant="row" token={WBTC} name="Wrapped Bitcoin" />
</div>With Icon
<TokenBalance
token="0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"
icon="https://assets.coingecko.com/coins/images/6319/small/usdc.png"
/>Custom Fiat Currency
<TokenBalance fiatCurrency="EUR" />Forex rates are fetched automatically. Supported currencies: any ISO 4217 code (EUR, GBP, JPY, etc.).
Manual Price Override
<TokenBalance token="0x..." price={1.0} />Useful for stablecoins or tokens not listed on DeFiLlama.
Hide Parts
<TokenBalance showFiat={false} />
<TokenBalance showIcon={false} showSymbol={false} />Custom Render
<TokenBalance token="0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48">
{({ formatted, symbol, fiatFormatted, isLoading }) => (
isLoading
? <span>Loading...</span>
: <span>{formatted} {symbol} ({fiatFormatted})</span>
)}
</TokenBalance>Balance Change Callback
<TokenBalance
onBalanceChange={(balance, prev) => {
if (prev !== undefined && balance > prev) {
console.log('Received tokens!')
}
}}
/>Multiple Tokens
Multiple TokenBalance components with the same parameters share a single RPC call via TanStack Query deduplication:
<TokenBalance token="0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48" />
{/* Same token - no extra RPC call */}
<TokenBalance token="0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48" />Specific Address
<TokenBalance address="0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045" />Render Data
When using the children render function, you receive a TokenBalanceRenderData object:
| Field | Type | Description |
|---|---|---|
icon | string | undefined | Token icon URL (passed via icon prop) |
balance | bigint | undefined | Raw balance in smallest unit (wei) |
decimals | number | undefined | Token decimals (18 for ETH, 6 for USDC) |
symbol | string | undefined | Token symbol (ETH, USDC) |
formatted | string | undefined | Human-readable balance with progressive scaling |
integerPart | string | undefined | Integer part of formatted balance (e.g. "1,234") |
fractionPart | string | undefined | Fractional part including dot (e.g. ".5678") |
isZero | boolean | True when balance is exactly 0n |
fiatValue | number | undefined | Fiat equivalent as raw number |
fiatFormatted | string | undefined | Fiat with currency symbol (e.g. "$1,234.57") |
isLoading | boolean | True while fetching |
isError | boolean | True if fetch failed |
error | Error | null | Error object if failed |
refetch | () => void | Manually trigger refetch |
integerPart and fractionPart exist so custom renderers can typeset the
fraction at a smaller size or muted color (the default UI does this).
Formatting
TokenBalance uses progressive decimal scaling based on the amount:
| Range | Decimals | Example |
|---|---|---|
| 0 - 9 | 5 | 1.23456 |
| 10 - 99 | 4 | 42.1234 |
| 100 - 999 | 3 | 500.123 |
| 1,000 - 9,999 | 2 | 2,500.12 |
| 10,000+ | suffix | 42.5k, 1.2m, 3.4b |
Dust Threshold
Amounts below 0.0001 display as < 0.0001. Override via formatOptions:
<TokenBalance formatOptions={{ dustThreshold: 0.001 }} />Locale
Number formatting follows the browser locale by default. Override:
<TokenBalance formatOptions={{ locale: 'de-DE' }} />Hooks
useTokenBalance
Headless hook for single token balance.
import { useTokenBalance } from '@txkit/react'
const { balance, decimals, symbol, formatted, isLoading, refetch } = useTokenBalance({
token: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
})| Option | Type | Description |
|---|---|---|
token | `0x${string}` | ERC-20 address. Omit for native token. |
address | `0x${string}` | Wallet address. Default: connected wallet. |
chainId | number | Chain ID. Default: current chain. |
refetchInterval | number | Polling interval in ms. |
enabled | boolean | Disable fetching. Default: true. |
useTokenBalances
Batch hook for multiple tokens. Optimizes ERC-20 calls into a single multicall request.
import { useTokenBalances } from '@txkit/react'
const balances = useTokenBalances({
tokens: [ 'native', '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48' ],
})
balances.forEach(({ symbol, formatted }) => {
console.log(`${symbol}: ${formatted}`)
})useTokenPrice
Hook for token price in fiat. Uses DeFiLlama API with automatic forex conversion.
import { useTokenPrice } from '@txkit/react'
const { price, isLoading } = useTokenPrice({
chainId: 1,
token: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
fiatCurrency: 'EUR',
})Labels
Override UI text by passing a partial TokenBalanceLabels object:
<TokenBalance labels={{ loading: 'Fetching...', error: 'Unavailable' }} />All Label Keys
| Key | Default |
|---|---|
loading | 'Loading...' |
error | 'Failed to load' |
Accessibility
TokenBalance includes built-in screen reader support:
role="status"andaria-live="polite"- announces balance updates without interruptingaria-atomic="true"- reads the full balance on each updatearia-busy- set totruewhile loading- Hidden status text provides a full sentence for screen readers (e.g. "Balance: 1.5 ETH, $3,200.00")