Production-ready Solana wallet connection components built with shadcn/ui and Next.js. These components are designed to be copied into your project and customized to match your needs.
# From repo root
pnpm install
# Run the example
cd examples/react
pnpm devOpen http://localhost:3000 to see the components in action.
All components are located in components/connector/radix-ui/ (Radix UI) and components/connector/base-ui/ (Base UI):
A fully-featured wallet connection button with dropdown menu.
Features:
- Opens wallet selection modal on click
- Shows wallet avatar and truncated address when connected
- Dropdown menu with copy address and disconnect actions
- Loading states during connection
- Fully styled with shadcn/ui components
Usage:
import { ConnectButton } from '@/components/connector/radix-ui';
export default function Header() {
return <ConnectButton />;
}A dialog for selecting and connecting to Solana wallets.
Features:
- Lists all available Solana wallets
- Shows wallet icons and names
- Detects installed vs. not installed wallets
- Provides installation links for popular wallets
- Handles connection errors gracefully
- Clean, accessible UI with shadcn Dialog
Usage:
import { WalletModal } from "@/components/connector/radix-ui"
const [open, setOpen] = useState(false)
<WalletModal open={open} onOpenChange={setOpen} />A dropdown for switching between multiple wallet accounts.
Features:
- Automatically hidden when only one account
- Dropdown menu showing all accounts
- Visual indicator for active account
- Truncated addresses for better UX
- Seamless account switching
Usage:
import { AccountSwitcher } from '@/components/connector/radix-ui';
export default function Header() {
return <AccountSwitcher />;
}A dropdown for switching between Solana networks.
Features:
- Supports Mainnet, Devnet, Testnet, and Localnet
- Color-coded badges for each network
- Persists selection across sessions
- Shows current network clearly
- Visual indicator for active cluster
Usage:
import { ClusterSelector } from '@/components/connector/radix-ui';
export default function Header() {
return <ClusterSelector />;
}These components are meant to be copied and customized:
- Copy the component files from
components/connector/radix-ui/orcomponents/connector/base-ui/to your project - Customize the styling by modifying Tailwind classes
- Extend functionality by adding your own features
- Replace icons or add animations as needed
// Change button colors
<ConnectButton className="bg-purple-500 hover:bg-purple-600" />
// Adjust dropdown position
<AccountSwitcher className="ml-auto" />These components use:
@solana/connector- Headless wallet connection logicshadcn/ui- UI components (Button, Dialog, Dropdown, etc.)lucide-react- Iconstailwindcss- Styling
components/
├── connector/
│ ├── radix-ui/ # Radix UI implementation
│ │ ├── connect-button.tsx # Main connection button
│ │ ├── wallet-modal.tsx # Wallet selection dialog
│ │ ├── wallet-dropdown-content.tsx
│ │ ├── account-switcher.tsx # Account switching dropdown
│ │ ├── cluster-selector.tsx # Network selection dropdown
│ │ └── index.ts # Barrel exports
│ ├── base-ui/ # Base UI implementation
│ │ ├── connect-button.tsx
│ │ ├── wallet-modal.tsx
│ │ ├── wallet-dropdown-content.tsx
│ │ └── index.ts
│ └── index.ts # Re-exports from both
├── ui/ # shadcn/ui base components
│ ├── button.tsx
│ ├── dialog.tsx
│ ├── dropdown-menu.tsx
│ └── ...
└── ui-base/ # Base UI primitive components
├── button.tsx
├── dialog.tsx
├── menu.tsx
└── ...
-
Install dependencies:
npm install @solana/connector npx shadcn@latest init npx shadcn@latest add button dialog dropdown-menu avatar badge card
-
Copy components:
# Copy Radix UI components cp -r components/connector/radix-ui your-project/components/connector/ # Or copy Base UI components cp -r components/connector/base-ui your-project/components/connector/
-
Use in your app:
// Radix UI import { ConnectButton } from '@/components/connector/radix-ui'; // Or Base UI import { ConnectButton } from '@/components/connector/base-ui';
Use these components as reference to build your own custom implementation:
- Study how hooks are used (
useWallet,useWalletConnectors,useConnectWallet,useDisconnectWallet,useAccount,useCluster) - Adapt the UI patterns to your design system
- Add custom features specific to your use case
See app/page.tsx for a complete example showing:
- Header with all components
- Connection status display
- Wallet information cards
- Network and account details
- Component documentation
This example includes support for server-backed signing using Fireblocks, Privy, or custom signers. This allows you to sign transactions from the frontend while keeping sensitive API keys secure on the server.
-
Configure Environment Variables
Create a
.env.localfile with your provider credentials:# Enable remote signer in the UI NEXT_PUBLIC_ENABLE_REMOTE_SIGNER=true # Auth token for the signing API (generate a secure random string) CONNECTOR_SIGNER_TOKEN=your-secure-token-here # Solana RPC URL (for signAndSend operations) SOLANA_RPC_URL=https://api.mainnet-beta.solana.com # --- Fireblocks Configuration --- FIREBLOCKS_API_KEY=your-api-key FIREBLOCKS_PRIVATE_KEY="-----BEGIN RSA PRIVATE KEY-----\n...\n-----END RSA PRIVATE KEY-----" FIREBLOCKS_VAULT_ID=0 # --- OR Privy Configuration --- # PRIVY_APP_ID=your-app-id # PRIVY_APP_SECRET=your-app-secret # PRIVY_WALLET_ID=wallet-id
-
Install Provider Dependencies (when available on npm)
The
@solana-keychain/*packages provide Fireblocks and Privy integrations. Once published, install only the one you need:# For Fireblocks (when published) pnpm add @solana-keychain/fireblocks # For Privy (when published) pnpm add @solana-keychain/privy
Note: If these packages aren't published yet, you can use the
customprovider type to implement your own signer (see route.ts for the interface). -
Run the Example
pnpm dev
The "Treasury Signer" will now appear in the wallet selection modal alongside browser wallets.
Browser Server (Next.js Route Handler)
│ │
│ 1. User selects "Treasury Signer" │
├───────────────────────────────────▶│
│ │ 2. GET /api/connector-signer
│◀───────────────────────────────────┤ Returns address + capabilities
│ │
│ 3. User initiates transaction │
├───────────────────────────────────▶│
│ │ 4. POST /api/connector-signer
│ │ { operation: "signTransaction" }
│ │
│ │ 5. Server signs with Fireblocks/Privy
│◀───────────────────────────────────┤
│ 6. Signed transaction returned │
- API Keys Stay Server-Side: Fireblocks/Privy credentials never leave the server
- Auth Token Required: All requests must include
Authorization: Bearer <token> - Policy Hooks: Optionally validate transactions before signing (see
route.ts) - No Client SDK Bloat: The browser only ships a tiny fetch-based adapter
Edit app/api/connector-signer/route.ts to add custom authorization:
const { GET, POST } = createRemoteSignerRouteHandlers({
provider: getProviderConfig(),
authorize: async request => {
// Example: verify user session
const session = await getServerSession(request);
return session?.user?.role === 'admin';
},
policy: {
validateTransaction: async (txBytes, request) => {
// Example: only allow transfers under 1 SOL
return true;
},
},
});- Error Handling: Add toast notifications for connection errors
- Analytics: Track wallet connections and network changes
- Accessibility: Components use semantic HTML and ARIA labels
- Performance: Components use React best practices (memoization, etc.)
- Mobile: Test on mobile devices and adjust as needed
- Remote Signing: Use strong auth tokens and consider rate limiting
- Combine Components: Use ConnectButton, AccountSwitcher, and ClusterSelector together in your header
- Conditional Rendering: AccountSwitcher automatically hides when not needed
- Persistence: ClusterSelector remembers the selected network across sessions
- Styling: All components accept
classNameprop for easy customization
These examples are meant to inspire and educate. Feel free to:
- Fork and customize for your needs
- Share improvements or variations
- Report issues or suggest features
Built with ❤️ using ConnectorKit, Next.js, and shadcn/ui