Why Solana + React?
Solana processes thousands of transactions per second with sub-cent fees. React is the dominant frontend framework. Together they form the most practical stack for building decentralized applications that actually feel like modern web apps.
This guide walks you through the essential building blocks: connecting wallets, reading accounts, sending transactions, and calling Anchor programs — all from a React frontend.
Prerequisites
- React 18+ project (Next.js, Vite, or CRA)
- Basic understanding of Solana (accounts, transactions, programs)
- A browser wallet like Phantom or Solflare
1. Install the Wallet Adapter
The @solana/wallet-adapter packages provide a unified interface for every Solana wallet.
npm install @solana/wallet-adapter-base \
@solana/wallet-adapter-react \
@solana/wallet-adapter-react-ui \
@solana/wallet-adapter-wallets \
@solana/web3.js2. Set Up the Provider
Wrap your app with the wallet and connection providers. This gives every child component access to the connected wallet and the RPC connection.
// src/providers/WalletProvider.tsx
import { useMemo } from "react";
import {
ConnectionProvider,
WalletProvider,
} from "@solana/wallet-adapter-react";
import { WalletModalProvider } from "@solana/wallet-adapter-react-ui";
import { PhantomWalletAdapter } from "@solana/wallet-adapter-wallets";
import { clusterApiUrl } from "@solana/web3.js";
import "@solana/wallet-adapter-react-ui/styles.css";
export function SolanaProviders({
children,
}: {
children: React.ReactNode;
}) {
Then wrap your app root:
// src/App.tsx or layout.tsx
import { SolanaProviders } from "./providers/WalletProvider";
export default function App({ children }) {
return (
<SolanaProviders>
{children}
</SolanaProviders>
);
}3. The Connect Wallet Button
The wallet adapter ships a ready-made button with a modal that lists all detected wallets.
import {
WalletMultiButton,
} from "@solana/wallet-adapter-react-ui";
export function Navbar() {
return (
<nav>
<h1>My Solana dApp</h1>
<WalletMultiButton />
</nav>
);
}That single component handles connect, disconnect, wallet selection, and displaying the truncated public key — all out of the box.
You can customize the button styling with the className prop or wrap useWallet() to build a fully custom connect experience.
4. Reading On-Chain Data
Use the useConnection hook to access the RPC connection and fetch account data.
Fetch SOL Balance
import { useConnection, useWallet } from "@solana/wallet-adapter-react";
import { LAMPORTS_PER_SOL } from "@solana/web3.js";
import { useEffect, useState } from "react";
export function Balance() {
const { connection } = useConnection();
const { publicKey } = useWallet();
const [balance, setBalance] = useState<number | null>(null);
useEffect(() => {
if (!
The onAccountChange subscription gives you real-time updates whenever the balance changes — no polling required.
Fetch Token Accounts
import { useConnection, useWallet } from "@solana/wallet-adapter-react";
import { TOKEN_PROGRAM_ID } from "@solana/spl-token";
export function useTokenAccounts() {
const { connection } = useConnection();
const { publicKey } = useWallet();
const fetchTokens = async () => {
if (!publicKey) return [];
const response = await connection.getParsedTokenAccountsByOwner(
publicKey,
{ programId: TOKEN_PROGRAM_ID
5. Sending Transactions
Simple SOL Transfer
import { useConnection, useWallet } from "@solana/wallet-adapter-react";
import {
PublicKey,
SystemProgram,
Transaction,
LAMPORTS_PER_SOL,
} from "@solana/web3.js";
export function SendSol() {
const { connection } = useConnection();
const { publicKey, sendTransaction } = useWallet();
const handleSend = async () => {
if (!publicKey) return;
const recipient = new
The sendTransaction function from the wallet adapter handles wallet signing and submission in one call.
6. Integrating an Anchor Program
If your on-chain program is built with Anchor, the client integration is even smoother thanks to the generated IDL and type-safe methods.
npm install @coral-xyz/anchorimport { useConnection, useWallet } from "@solana/wallet-adapter-react";
import { Program, AnchorProvider } from "@coral-xyz/anchor";
import { PublicKey } from "@solana/web3.js";
import idl from "./idl/counter.json";
const PROGRAM_ID = new PublicKey("YOUR_PROGRAM_ID");
export function useCounterProgram() {
const { connection } = useConnection();
const wallet = useWallet();
const getProgram = () => {
const provider
Copy the IDL from target/idl/your_program.json after running anchor build. The IDL gives the Anchor client full type information about your program's instructions and accounts.
7. Error Handling Patterns
Solana transactions can fail for many reasons. Here is a robust pattern:
import { WalletNotConnectedError } from "@solana/wallet-adapter-base";
async function safeSend(
sendTransaction: Function,
transaction: Transaction,
connection: Connection,
publicKey: PublicKey | null
) {
if (!publicKey) throw new WalletNotConnectedError();
try {
const { blockhash, lastValidBlockHeight } =
await connection.getLatestBlockhash();
transaction.recentBlockhash = blockhash;
8. Useful Hooks Cheat Sheet
| Hook | Package | Purpose |
|---|---|---|
useWallet() | @solana/wallet-adapter-react | Access connected wallet, publicKey, signTransaction |
useConnection() | @solana/wallet-adapter-react | Access the Solana RPC connection |
useAnchorWallet() | @solana/wallet-adapter-react | Wallet object compatible with AnchorProvider |
useWalletModal() | @solana/wallet-adapter-react-ui | Programmatically open/close wallet selection modal |
Project Structure Recommendation
src/
├── providers/
│ └── WalletProvider.tsx
├── hooks/
│ ├── useBalance.ts
│ ├── useTokenAccounts.ts
│ └── useProgram.ts # Anchor program hook
├── components/
│ ├── Navbar.tsx # WalletMultiButton
│ ├── Balance.tsx
│ ├── SendSol.tsx
│ └── ProgramInteraction.tsx
├── idl/
│ └── your_program.json # Anchor IDL
└── App.tsx
Wrapping Up
With the Solana wallet adapter and a few hundred lines of React, you can build fully functional decentralized applications. The key building blocks are:
- Providers —
ConnectionProvider+WalletProviderwrap your app - Wallet hooks —
useWallet()anduseConnection()give you everything - Transactions — build with
Transaction, sign withsendTransaction - Anchor integration —
Programclass with IDL for type-safe program calls - Subscriptions —
onAccountChangefor real-time UI updates
From here, explore SPL tokens, Metaplex NFTs, or build a full DEX interface. The React patterns stay the same — only the program interactions change.