Addons

Wallet Balance

Displays SOL balance with refresh. Requires connect-button.

Preview

"use client";import { useBalance } from "@solana/connector/react";import { RefreshCw } from "lucide-react";import { cn } from "@/lib/utils";interface WalletBalanceProps {  /** Whether to auto-refresh balance (default: true) */  autoRefresh?: boolean;  /** Refresh interval in milliseconds (default: 30000) */  refreshInterval?: number;  /** Show refresh button (default: true) */  showRefresh?: boolean;  /** Custom className */  className?: string;}export function WalletBalance({  autoRefresh = true,  refreshInterval = 30000,  showRefresh = true,  className,}: WalletBalanceProps) {  const { solBalance, isLoading, refetch } = useBalance({    autoRefresh,    refreshInterval,  });  return (    <div className={cn("rounded-xl border bg-muted/50 p-4", className)}>      <div className="flex items-center justify-between mb-1">        <span className="text-sm text-muted-foreground">Balance</span>        {showRefresh && (          <button            type="button"            onClick={() => refetch()}            disabled={isLoading}            className="p-1 hover:bg-accent rounded transition-colors disabled:opacity-50"          >            <RefreshCw              className={cn("h-3.5 w-3.5", isLoading && "animate-spin")}            />          </button>        )}      </div>      <div className="tabular-nums text-2xl font-bold">        {isLoading ? (          <div className="h-8 w-32 bg-muted animate-pulse rounded" />        ) : solBalance !== null ? (          `${solBalance.toFixed(4)} SOL`        ) : (          "-- SOL"        )}      </div>    </div>  );}

Prerequisites

Complete the installation guide and install Connect Button before using this addon.

Try the Demo

Want to see it working immediately without manual wiring? Install the demo:

npx shadcn@latest add https://nitso.fun/r/wallet-balance-demo.json
pnpm dlx shadcn@latest add https://nitso.fun/r/wallet-balance-demo.json
yarn dlx shadcn@latest add https://nitso.fun/r/wallet-balance-demo.json
bunx --bun shadcn@latest add https://nitso.fun/r/wallet-balance-demo.json

This installs wallet-balance-demo.tsx into your components/ folder. Drop it anywhere:

import { WalletBalanceDemo } from '@/components/wallet-balance-demo';

export default function Page() {
  return <WalletBalanceDemo />;
}

Delete it when you're ready to wire things up yourself.

Installation

npx shadcn@latest add https://nitso.fun/r/wallet-balance.json
pnpm dlx shadcn@latest add https://nitso.fun/r/wallet-balance.json
yarn dlx shadcn@latest add https://nitso.fun/r/wallet-balance.json
bunx --bun shadcn@latest add https://nitso.fun/r/wallet-balance.json

Copy the source code

"use client";import { useBalance } from "@solana/connector/react";import { RefreshCw } from "lucide-react";import { cn } from "@/lib/utils";interface WalletBalanceProps {  /** Whether to auto-refresh balance (default: true) */  autoRefresh?: boolean;  /** Refresh interval in milliseconds (default: 30000) */  refreshInterval?: number;  /** Show refresh button (default: true) */  showRefresh?: boolean;  /** Custom className */  className?: string;}export function WalletBalance({  autoRefresh = true,  refreshInterval = 30000,  showRefresh = true,  className,}: WalletBalanceProps) {  const { solBalance, isLoading, refetch } = useBalance({    autoRefresh,    refreshInterval,  });  return (    <div className={cn("rounded-xl border bg-muted/50 p-4", className)}>      <div className="flex items-center justify-between mb-1">        <span className="text-sm text-muted-foreground">Balance</span>        {showRefresh && (          <button            type="button"            onClick={() => refetch()}            disabled={isLoading}            className="p-1 hover:bg-accent rounded transition-colors disabled:opacity-50"          >            <RefreshCw              className={cn("h-3.5 w-3.5", isLoading && "animate-spin")}            />          </button>        )}      </div>      <div className="tabular-nums text-2xl font-bold">        {isLoading ? (          <div className="h-8 w-32 bg-muted animate-pulse rounded" />        ) : solBalance !== null ? (          `${solBalance.toFixed(4)} SOL`        ) : (          "-- SOL"        )}      </div>    </div>  );}

Wiring

Update the file where you use <ConnectButton /> (e.g. your header or layout):

Before:

components/header.tsx
import { ConnectButton } from "@/components/nitso/connect-button/";

export function Header() {
  return (
    <nav>
      <ConnectButton />
    </nav>
  );
}

After:

components/header.tsx
import { ConnectButton } from "@/components/nitso/connect-button/";
import {
  WalletDropdownContent, 
  type WalletDropdownContentProps, 
} from "@/components/nitso/connect-button/"; 
import { WalletBalance } from "@/components/nitso/addons/wallet-balance/"; 

function WalletDropdownWithBalance(props: WalletDropdownContentProps) { 
  return ( 
    <WalletDropdownContent {...props}> // [!code ++]
      <WalletBalance /> // [!code ++]
    </WalletDropdownContent> 
  ); 
} 

export function Header() {
  return (
    <nav>
      <ConnectButton /> // [!code --]
      <ConnectButton dropdownContent={WalletDropdownWithBalance} /> // [!code ++]
    </nav>
  );
}

WalletBalance plugs into the children slot of WalletDropdownContent, rendering it between the wallet header and the disconnect button.

Combining with Network Switcher

If you already have the Network Switcher wired up, add WalletBalance as a child:

components/header.tsx
import { useState } from "react";
import { ConnectButton } from "@/components/nitso/connect-button/";
import {
  WalletDropdownContent,
  type WalletDropdownContentProps,
} from "@/components/nitso/connect-button/";
import {
  NetworkSwitcherButton,
  NetworkSwitcherView,
} from "@/components/nitso/addons/network-switcher/";
import { WalletBalance } from "@/components/nitso/addons/wallet-balance/";

function WalletDropdownWithNetwork(props: WalletDropdownContentProps) {
  const [view, setView] = useState<"wallet" | "network">("wallet");

  if (view === "network") {
    return <NetworkSwitcherView onBack={() => setView("wallet")} />;
  }

  return (
    <WalletDropdownContent
      {...props}
      actions={<NetworkSwitcherButton onClick={() => setView("network")} />}
    >
      <WalletBalance /> // [!code ++]
    </WalletDropdownContent>
  );
}

export function Header() {
  return (
    <nav>
      <ConnectButton dropdownContent={WalletDropdownWithNetwork} />
    </nav>
  );
}

Props

PropTypeDefaultDescription
autoRefreshbooleantrueWhether to auto-refresh balance in the background
refreshIntervalnumber30000Interval in milliseconds between refreshes, only applies when autoRefresh is true
showRefreshbooleantrueWhether to show the manual refresh button
classNamestringCustom className for the container
// Default — polls every 30s, manual refresh button visible
<WalletBalance />

// Disable background polling
<WalletBalance autoRefresh={false} />

// Poll every 60s
<WalletBalance autoRefresh={true} refreshInterval={60000} />

// Hide the refresh button
<WalletBalance showRefresh={false} />

On this page